blob: f23f3825ca987a9d24fd3145953c3231ac9e82ed [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,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100501 StrictModeFlag strict_mode) {
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(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100504 Code::STORE_IC, type, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000505 Object* code = receiver->map()->FindInCodeCache(name, flags);
506 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100507 StoreStubCompiler compiler(strict_mode);
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 Murdoche0cee9b2011-05-25 10:26:03 +0100524MaybeObject* StubCache::ComputeKeyedStoreSpecialized(
525 JSObject* receiver,
526 StrictModeFlag strict_mode) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100527 Code::Flags flags =
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100528 Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL, strict_mode);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100529 String* name = Heap::KeyedStoreSpecialized_symbol();
530 Object* code = receiver->map()->FindInCodeCache(name, flags);
531 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100532 KeyedStoreStubCompiler compiler(strict_mode);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100533 { MaybeObject* maybe_code = compiler.CompileStoreSpecialized(receiver);
534 if (!maybe_code->ToObject(&code)) return maybe_code;
535 }
536 PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
537 Object* result;
538 { MaybeObject* maybe_result =
539 receiver->UpdateMapCodeCache(name, Code::cast(code));
540 if (!maybe_result->ToObject(&result)) return maybe_result;
541 }
542 }
543 return code;
544}
545
546
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100547MaybeObject* StubCache::ComputeKeyedStorePixelArray(
548 JSObject* receiver,
549 StrictModeFlag strict_mode) {
550 // Using NORMAL as the PropertyType for array element stores is a misuse. The
551 // generated stub always accesses fast elements, not slow-mode fields, but
552 // some property type is required for the stub lookup. Note that overloading
553 // the NORMAL PropertyType is only safe as long as no stubs are generated for
554 // other keyed field stores. This is guaranteed to be the case since all field
555 // keyed stores that are not array elements go through a generic builtin stub.
556 Code::Flags flags =
557 Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL, strict_mode);
558 String* name = Heap::KeyedStorePixelArray_symbol();
559 Object* code = receiver->map()->FindInCodeCache(name, flags);
560 if (code->IsUndefined()) {
561 KeyedStoreStubCompiler compiler(strict_mode);
562 { MaybeObject* maybe_code = compiler.CompileStorePixelArray(receiver);
563 if (!maybe_code->ToObject(&code)) return maybe_code;
564 }
565 PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
566 Object* result;
567 { MaybeObject* maybe_result =
568 receiver->UpdateMapCodeCache(name, Code::cast(code));
569 if (!maybe_result->ToObject(&result)) return maybe_result;
570 }
571 }
572 return code;
573}
574
575
Steve Block1e0659c2011-05-24 12:43:12 +0100576namespace {
577
578ExternalArrayType ElementsKindToExternalArrayType(JSObject::ElementsKind kind) {
579 switch (kind) {
580 case JSObject::EXTERNAL_BYTE_ELEMENTS:
581 return kExternalByteArray;
582 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
583 return kExternalUnsignedByteArray;
584 case JSObject::EXTERNAL_SHORT_ELEMENTS:
585 return kExternalShortArray;
586 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
587 return kExternalUnsignedShortArray;
588 case JSObject::EXTERNAL_INT_ELEMENTS:
589 return kExternalIntArray;
590 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
591 return kExternalUnsignedIntArray;
592 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
593 return kExternalFloatArray;
594 default:
595 UNREACHABLE();
596 return static_cast<ExternalArrayType>(0);
597 }
598}
599
600} // anonymous namespace
601
602
603MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray(
604 JSObject* receiver,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100605 bool is_store,
606 StrictModeFlag strict_mode) {
Steve Block1e0659c2011-05-24 12:43:12 +0100607 Code::Flags flags =
608 Code::ComputeMonomorphicFlags(
609 is_store ? Code::KEYED_STORE_IC : Code::KEYED_LOAD_IC,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100610 NORMAL,
611 strict_mode);
Steve Block1e0659c2011-05-24 12:43:12 +0100612 ExternalArrayType array_type =
613 ElementsKindToExternalArrayType(receiver->GetElementsKind());
614 String* name =
615 is_store ? Heap::KeyedStoreExternalArray_symbol()
616 : Heap::KeyedLoadExternalArray_symbol();
617 // Use the global maps for the particular external array types,
618 // rather than the receiver's map, when looking up the cached code,
619 // so that we actually canonicalize these stubs.
620 Map* map = Heap::MapForExternalArrayType(array_type);
621 Object* code = map->FindInCodeCache(name, flags);
622 if (code->IsUndefined()) {
623 ExternalArrayStubCompiler compiler;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100624 { MaybeObject* maybe_code = is_store
625 ? compiler.CompileKeyedStoreStub(array_type, flags)
626 : compiler.CompileKeyedLoadStub(array_type, flags);
Steve Block1e0659c2011-05-24 12:43:12 +0100627 if (!maybe_code->ToObject(&code)) return maybe_code;
628 }
629 if (is_store) {
630 PROFILE(
631 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
632 } else {
633 PROFILE(
634 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
635 }
636 Object* result;
637 { MaybeObject* maybe_result =
638 map->UpdateCodeCache(name, Code::cast(code));
639 if (!maybe_result->ToObject(&result)) return maybe_result;
640 }
641 }
642 return code;
643}
644
645
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100646MaybeObject* StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
647 return Builtins::builtin((strict_mode == kStrictMode)
Steve Block1e0659c2011-05-24 12:43:12 +0100648 ? Builtins::StoreIC_Normal_Strict
649 : Builtins::StoreIC_Normal);
Steve Block8defd9f2010-07-08 12:39:36 +0100650}
651
652
John Reck59135872010-11-02 12:39:01 -0700653MaybeObject* StubCache::ComputeStoreGlobal(String* name,
654 GlobalObject* receiver,
Steve Block1e0659c2011-05-24 12:43:12 +0100655 JSGlobalPropertyCell* cell,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100656 StrictModeFlag strict_mode) {
Steve Block1e0659c2011-05-24 12:43:12 +0100657 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100658 Code::STORE_IC, NORMAL, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000659 Object* code = receiver->map()->FindInCodeCache(name, flags);
660 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100661 StoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700662 { MaybeObject* maybe_code =
663 compiler.CompileStoreGlobal(receiver, cell, name);
664 if (!maybe_code->ToObject(&code)) return maybe_code;
665 }
Steve Block8defd9f2010-07-08 12:39:36 +0100666 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100667 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700668 Object* result;
669 { MaybeObject* maybe_result =
670 receiver->UpdateMapCodeCache(name, Code::cast(code));
671 if (!maybe_result->ToObject(&result)) return maybe_result;
672 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000673 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100674 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000675}
676
677
Steve Block1e0659c2011-05-24 12:43:12 +0100678MaybeObject* StubCache::ComputeStoreCallback(
679 String* name,
680 JSObject* receiver,
681 AccessorInfo* callback,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100682 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000683 ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
Steve Block1e0659c2011-05-24 12:43:12 +0100684 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100685 Code::STORE_IC, CALLBACKS, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000686 Object* code = receiver->map()->FindInCodeCache(name, flags);
687 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100688 StoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700689 { MaybeObject* maybe_code =
690 compiler.CompileStoreCallback(receiver, callback, name);
691 if (!maybe_code->ToObject(&code)) return maybe_code;
692 }
Steve Block6ded16b2010-05-10 14:33:55 +0100693 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100694 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700695 Object* result;
696 { MaybeObject* maybe_result =
697 receiver->UpdateMapCodeCache(name, Code::cast(code));
698 if (!maybe_result->ToObject(&result)) return maybe_result;
699 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000700 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100701 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000702}
703
704
Steve Block1e0659c2011-05-24 12:43:12 +0100705MaybeObject* StubCache::ComputeStoreInterceptor(
706 String* name,
707 JSObject* receiver,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100708 StrictModeFlag strict_mode) {
Steve Block1e0659c2011-05-24 12:43:12 +0100709 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100710 Code::STORE_IC, INTERCEPTOR, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000711 Object* code = receiver->map()->FindInCodeCache(name, flags);
712 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100713 StoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700714 { MaybeObject* maybe_code =
715 compiler.CompileStoreInterceptor(receiver, name);
716 if (!maybe_code->ToObject(&code)) return maybe_code;
717 }
Steve Block6ded16b2010-05-10 14:33:55 +0100718 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100719 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700720 Object* result;
721 { MaybeObject* maybe_result =
722 receiver->UpdateMapCodeCache(name, Code::cast(code));
723 if (!maybe_result->ToObject(&result)) return maybe_result;
724 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000725 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100726 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000727}
728
729
John Reck59135872010-11-02 12:39:01 -0700730MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
731 JSObject* receiver,
732 int field_index,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100733 Map* transition,
734 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000735 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100736 Code::Flags flags = Code::ComputeMonomorphicFlags(
737 Code::KEYED_STORE_IC, type, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000738 Object* code = receiver->map()->FindInCodeCache(name, flags);
739 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100740 KeyedStoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700741 { MaybeObject* maybe_code =
742 compiler.CompileStoreField(receiver, field_index, transition, name);
743 if (!maybe_code->ToObject(&code)) return maybe_code;
744 }
Steve Block6ded16b2010-05-10 14:33:55 +0100745 PROFILE(CodeCreateEvent(
746 Logger::KEYED_STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100747 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700748 Object* result;
749 { MaybeObject* maybe_result =
750 receiver->UpdateMapCodeCache(name, Code::cast(code));
751 if (!maybe_result->ToObject(&result)) return maybe_result;
752 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000753 }
754 return code;
755}
756
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100757#define CALL_LOGGER_TAG(kind, type) \
758 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
Steve Blocka7e24c12009-10-30 11:49:00 +0000759
John Reck59135872010-11-02 12:39:01 -0700760MaybeObject* StubCache::ComputeCallConstant(int argc,
761 InLoopFlag in_loop,
762 Code::Kind kind,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100763 Code::ExtraICState extra_ic_state,
John Reck59135872010-11-02 12:39:01 -0700764 String* name,
765 Object* object,
766 JSObject* holder,
767 JSFunction* function) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000768 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100769 InlineCacheHolderFlag cache_holder =
770 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100771 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000772
773 // Compute check type based on receiver/holder.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100774 CheckType check = RECEIVER_MAP_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000775 if (object->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100776 check = STRING_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000777 } else if (object->IsNumber()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100778 check = NUMBER_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000779 } else if (object->IsBoolean()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100780 check = BOOLEAN_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000781 }
782
Ben Murdochb8e0da22011-05-16 14:20:40 +0100783 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
784 CONSTANT_FUNCTION,
785 extra_ic_state,
786 cache_holder,
787 in_loop,
788 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100789 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000790 if (code->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000791 // If the function hasn't been compiled yet, we cannot do it now
792 // because it may cause GC. To avoid this issue, we return an
793 // internal error which will make sure we do not update any
794 // caches.
795 if (!function->is_compiled()) return Failure::InternalError();
796 // Compile the stub - only create stubs for fully compiled functions.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100797 CallStubCompiler compiler(
798 argc, in_loop, kind, extra_ic_state, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700799 { MaybeObject* maybe_code =
800 compiler.CompileCallConstant(object, holder, function, name, check);
801 if (!maybe_code->ToObject(&code)) return maybe_code;
802 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100803 Code::cast(code)->set_check_type(check);
Steve Blocka7e24c12009-10-30 11:49:00 +0000804 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100805 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
806 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100807 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700808 Object* result;
809 { MaybeObject* maybe_result =
810 map_holder->UpdateMapCodeCache(name, Code::cast(code));
811 if (!maybe_result->ToObject(&result)) return maybe_result;
812 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000813 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100814 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000815}
816
817
John Reck59135872010-11-02 12:39:01 -0700818MaybeObject* StubCache::ComputeCallField(int argc,
819 InLoopFlag in_loop,
820 Code::Kind kind,
821 String* name,
822 Object* object,
823 JSObject* holder,
824 int index) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000825 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100826 InlineCacheHolderFlag cache_holder =
827 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100828 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000829
830 // TODO(1233596): We cannot do receiver map check for non-JS objects
831 // because they may be represented as immediates without a
832 // map. Instead, we check against the map in the holder.
833 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
834 object = holder;
835 }
836
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100837 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000838 FIELD,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100839 Code::kNoExtraICState,
Steve Block8defd9f2010-07-08 12:39:36 +0100840 cache_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000841 in_loop,
842 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100843 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000844 if (code->IsUndefined()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100845 CallStubCompiler compiler(
846 argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700847 { MaybeObject* maybe_code =
848 compiler.CompileCallField(JSObject::cast(object),
849 holder,
850 index,
851 name);
852 if (!maybe_code->ToObject(&code)) return maybe_code;
853 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000854 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100855 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
856 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100857 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700858 Object* result;
859 { MaybeObject* maybe_result =
860 map_holder->UpdateMapCodeCache(name, Code::cast(code));
861 if (!maybe_result->ToObject(&result)) return maybe_result;
862 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000863 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100864 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000865}
866
867
John Reck59135872010-11-02 12:39:01 -0700868MaybeObject* StubCache::ComputeCallInterceptor(int argc,
869 Code::Kind kind,
870 String* name,
871 Object* object,
872 JSObject* holder) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000873 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100874 InlineCacheHolderFlag cache_holder =
875 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100876 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000877
878 // TODO(1233596): We cannot do receiver map check for non-JS objects
879 // because they may be represented as immediates without a
880 // map. Instead, we check against the map in the holder.
881 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
882 object = holder;
883 }
884
Ben Murdochb8e0da22011-05-16 14:20:40 +0100885 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
886 INTERCEPTOR,
887 Code::kNoExtraICState,
888 cache_holder,
889 NOT_IN_LOOP,
890 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100891 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000892 if (code->IsUndefined()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100893 CallStubCompiler compiler(
894 argc, NOT_IN_LOOP, kind, Code::kNoExtraICState, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700895 { MaybeObject* maybe_code =
896 compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
897 if (!maybe_code->ToObject(&code)) return maybe_code;
898 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000899 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100900 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
901 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100902 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700903 Object* result;
904 { MaybeObject* maybe_result =
905 map_holder->UpdateMapCodeCache(name, Code::cast(code));
906 if (!maybe_result->ToObject(&result)) return maybe_result;
907 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000908 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100909 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000910}
911
912
John Reck59135872010-11-02 12:39:01 -0700913MaybeObject* StubCache::ComputeCallNormal(int argc,
914 InLoopFlag in_loop,
915 Code::Kind kind,
916 String* name,
917 JSObject* receiver) {
918 Object* code;
919 { MaybeObject* maybe_code = ComputeCallNormal(argc, in_loop, kind);
920 if (!maybe_code->ToObject(&code)) return maybe_code;
921 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100922 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000923}
924
925
John Reck59135872010-11-02 12:39:01 -0700926MaybeObject* StubCache::ComputeCallGlobal(int argc,
927 InLoopFlag in_loop,
928 Code::Kind kind,
929 String* name,
930 JSObject* receiver,
931 GlobalObject* holder,
932 JSGlobalPropertyCell* cell,
933 JSFunction* function) {
Steve Block8defd9f2010-07-08 12:39:36 +0100934 InlineCacheHolderFlag cache_holder =
935 IC::GetCodeCacheForObject(receiver, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100936 JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100937 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
938 NORMAL,
939 Code::kNoExtraICState,
940 cache_holder,
941 in_loop,
942 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100943 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000944 if (code->IsUndefined()) {
945 // If the function hasn't been compiled yet, we cannot do it now
946 // because it may cause GC. To avoid this issue, we return an
947 // internal error which will make sure we do not update any
948 // caches.
949 if (!function->is_compiled()) return Failure::InternalError();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100950 CallStubCompiler compiler(
951 argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700952 { MaybeObject* maybe_code =
953 compiler.CompileCallGlobal(receiver, holder, cell, function, name);
954 if (!maybe_code->ToObject(&code)) return maybe_code;
955 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000956 ASSERT_EQ(flags, Code::cast(code)->flags());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100957 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
958 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100959 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700960 Object* result;
961 { MaybeObject* maybe_result =
962 map_holder->UpdateMapCodeCache(name, Code::cast(code));
963 if (!maybe_result->ToObject(&result)) return maybe_result;
964 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000965 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100966 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000967}
968
969
970static Object* GetProbeValue(Code::Flags flags) {
971 // Use raw_unchecked... so we don't get assert failures during GC.
972 NumberDictionary* dictionary = Heap::raw_unchecked_non_monomorphic_cache();
973 int entry = dictionary->FindEntry(flags);
974 if (entry != -1) return dictionary->ValueAt(entry);
975 return Heap::raw_unchecked_undefined_value();
976}
977
978
John Reck59135872010-11-02 12:39:01 -0700979MUST_USE_RESULT static MaybeObject* ProbeCache(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000980 Object* probe = GetProbeValue(flags);
981 if (probe != Heap::undefined_value()) return probe;
982 // Seed the cache with an undefined value to make sure that any
983 // generated code object can always be inserted into the cache
984 // without causing allocation failures.
John Reck59135872010-11-02 12:39:01 -0700985 Object* result;
986 { MaybeObject* maybe_result =
987 Heap::non_monomorphic_cache()->AtNumberPut(flags,
988 Heap::undefined_value());
989 if (!maybe_result->ToObject(&result)) return maybe_result;
990 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000991 Heap::public_set_non_monomorphic_cache(NumberDictionary::cast(result));
992 return probe;
993}
994
995
John Reck59135872010-11-02 12:39:01 -0700996static MaybeObject* FillCache(MaybeObject* maybe_code) {
997 Object* code;
998 if (maybe_code->ToObject(&code)) {
999 if (code->IsCode()) {
1000 int entry =
1001 Heap::non_monomorphic_cache()->FindEntry(
1002 Code::cast(code)->flags());
1003 // The entry must be present see comment in ProbeCache.
1004 ASSERT(entry != -1);
1005 ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) ==
1006 Heap::undefined_value());
1007 Heap::non_monomorphic_cache()->ValueAtPut(entry, code);
1008 CHECK(GetProbeValue(Code::cast(code)->flags()) == code);
1009 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001010 }
John Reck59135872010-11-02 12:39:01 -07001011 return maybe_code;
Steve Blocka7e24c12009-10-30 11:49:00 +00001012}
1013
1014
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001015Code* StubCache::FindCallInitialize(int argc,
1016 InLoopFlag in_loop,
1017 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001018 Code::Flags flags = Code::ComputeFlags(kind,
1019 in_loop,
1020 UNINITIALIZED,
1021 Code::kNoExtraICState,
1022 NORMAL,
1023 argc);
John Reck59135872010-11-02 12:39:01 -07001024 Object* result = ProbeCache(flags)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001025 ASSERT(!result->IsUndefined());
1026 // This might be called during the marking phase of the collector
1027 // hence the unchecked cast.
1028 return reinterpret_cast<Code*>(result);
1029}
1030
1031
John Reck59135872010-11-02 12:39:01 -07001032MaybeObject* StubCache::ComputeCallInitialize(int argc,
1033 InLoopFlag in_loop,
1034 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001035 Code::Flags flags = Code::ComputeFlags(kind,
1036 in_loop,
1037 UNINITIALIZED,
1038 Code::kNoExtraICState,
1039 NORMAL,
1040 argc);
John Reck59135872010-11-02 12:39:01 -07001041 Object* probe;
1042 { MaybeObject* maybe_probe = ProbeCache(flags);
1043 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1044 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001045 if (!probe->IsUndefined()) return probe;
1046 StubCompiler compiler;
1047 return FillCache(compiler.CompileCallInitialize(flags));
1048}
1049
1050
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001051Handle<Code> StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop) {
1052 if (in_loop == IN_LOOP) {
1053 // Force the creation of the corresponding stub outside loops,
1054 // because it may be used when clearing the ICs later - it is
1055 // possible for a series of IC transitions to lose the in-loop
1056 // information, and the IC clearing code can't generate a stub
1057 // that it needs so we need to ensure it is generated already.
1058 ComputeCallInitialize(argc, NOT_IN_LOOP);
1059 }
1060 CALL_HEAP_FUNCTION(ComputeCallInitialize(argc, in_loop, Code::CALL_IC), Code);
1061}
1062
1063
1064Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
1065 InLoopFlag in_loop) {
1066 if (in_loop == IN_LOOP) {
1067 // Force the creation of the corresponding stub outside loops,
1068 // because it may be used when clearing the ICs later - it is
1069 // possible for a series of IC transitions to lose the in-loop
1070 // information, and the IC clearing code can't generate a stub
1071 // that it needs so we need to ensure it is generated already.
1072 ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
1073 }
1074 CALL_HEAP_FUNCTION(
1075 ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC), Code);
1076}
1077
1078
John Reck59135872010-11-02 12:39:01 -07001079MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc,
1080 InLoopFlag in_loop,
1081 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001082 Code::Flags flags = Code::ComputeFlags(kind,
1083 in_loop,
1084 PREMONOMORPHIC,
1085 Code::kNoExtraICState,
1086 NORMAL,
1087 argc);
John Reck59135872010-11-02 12:39:01 -07001088 Object* probe;
1089 { MaybeObject* maybe_probe = ProbeCache(flags);
1090 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1091 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001092 if (!probe->IsUndefined()) return probe;
1093 StubCompiler compiler;
1094 return FillCache(compiler.CompileCallPreMonomorphic(flags));
1095}
1096
1097
John Reck59135872010-11-02 12:39:01 -07001098MaybeObject* StubCache::ComputeCallNormal(int argc,
1099 InLoopFlag in_loop,
1100 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001101 Code::Flags flags = Code::ComputeFlags(kind,
1102 in_loop,
1103 MONOMORPHIC,
1104 Code::kNoExtraICState,
1105 NORMAL,
1106 argc);
John Reck59135872010-11-02 12:39:01 -07001107 Object* probe;
1108 { MaybeObject* maybe_probe = ProbeCache(flags);
1109 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1110 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001111 if (!probe->IsUndefined()) return probe;
1112 StubCompiler compiler;
1113 return FillCache(compiler.CompileCallNormal(flags));
1114}
1115
1116
John Reck59135872010-11-02 12:39:01 -07001117MaybeObject* StubCache::ComputeCallMegamorphic(int argc,
1118 InLoopFlag in_loop,
1119 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001120 Code::Flags flags = Code::ComputeFlags(kind,
1121 in_loop,
1122 MEGAMORPHIC,
1123 Code::kNoExtraICState,
1124 NORMAL,
1125 argc);
John Reck59135872010-11-02 12:39:01 -07001126 Object* probe;
1127 { MaybeObject* maybe_probe = ProbeCache(flags);
1128 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1129 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001130 if (!probe->IsUndefined()) return probe;
1131 StubCompiler compiler;
1132 return FillCache(compiler.CompileCallMegamorphic(flags));
1133}
1134
1135
John Reck59135872010-11-02 12:39:01 -07001136MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001137 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
1138 // and monomorphic stubs are not mixed up together in the stub cache.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001139 Code::Flags flags = Code::ComputeFlags(kind,
1140 NOT_IN_LOOP,
1141 MONOMORPHIC_PROTOTYPE_FAILURE,
1142 Code::kNoExtraICState,
1143 NORMAL,
1144 argc,
1145 OWN_MAP);
John Reck59135872010-11-02 12:39:01 -07001146 Object* probe;
1147 { MaybeObject* maybe_probe = ProbeCache(flags);
1148 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1149 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001150 if (!probe->IsUndefined()) return probe;
1151 StubCompiler compiler;
1152 return FillCache(compiler.CompileCallMiss(flags));
1153}
1154
1155
1156#ifdef ENABLE_DEBUGGER_SUPPORT
John Reck59135872010-11-02 12:39:01 -07001157MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001158 Code::Flags flags = Code::ComputeFlags(kind,
1159 NOT_IN_LOOP,
1160 DEBUG_BREAK,
1161 Code::kNoExtraICState,
1162 NORMAL,
1163 argc);
John Reck59135872010-11-02 12:39:01 -07001164 Object* probe;
1165 { MaybeObject* maybe_probe = ProbeCache(flags);
1166 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1167 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001168 if (!probe->IsUndefined()) return probe;
1169 StubCompiler compiler;
1170 return FillCache(compiler.CompileCallDebugBreak(flags));
1171}
1172
1173
John Reck59135872010-11-02 12:39:01 -07001174MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(int argc,
1175 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001176 Code::Flags flags = Code::ComputeFlags(kind,
1177 NOT_IN_LOOP,
1178 DEBUG_PREPARE_STEP_IN,
1179 Code::kNoExtraICState,
1180 NORMAL,
1181 argc);
John Reck59135872010-11-02 12:39:01 -07001182 Object* probe;
1183 { MaybeObject* maybe_probe = ProbeCache(flags);
1184 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1185 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001186 if (!probe->IsUndefined()) return probe;
1187 StubCompiler compiler;
1188 return FillCache(compiler.CompileCallDebugPrepareStepIn(flags));
1189}
1190#endif
1191
1192
Steve Blocka7e24c12009-10-30 11:49:00 +00001193void StubCache::Clear() {
1194 for (int i = 0; i < kPrimaryTableSize; i++) {
1195 primary_[i].key = Heap::empty_string();
1196 primary_[i].value = Builtins::builtin(Builtins::Illegal);
1197 }
1198 for (int j = 0; j < kSecondaryTableSize; j++) {
1199 secondary_[j].key = Heap::empty_string();
1200 secondary_[j].value = Builtins::builtin(Builtins::Illegal);
1201 }
1202}
1203
1204
Ben Murdochb0fe1622011-05-05 13:52:32 +01001205void StubCache::CollectMatchingMaps(ZoneMapList* types,
1206 String* name,
1207 Code::Flags flags) {
1208 for (int i = 0; i < kPrimaryTableSize; i++) {
1209 if (primary_[i].key == name) {
1210 Map* map = primary_[i].value->FindFirstMap();
1211 // Map can be NULL, if the stub is constant function call
1212 // with a primitive receiver.
1213 if (map == NULL) continue;
1214
1215 int offset = PrimaryOffset(name, flags, map);
1216 if (entry(primary_, offset) == &primary_[i]) {
1217 types->Add(Handle<Map>(map));
1218 }
1219 }
1220 }
1221
1222 for (int i = 0; i < kSecondaryTableSize; i++) {
1223 if (secondary_[i].key == name) {
1224 Map* map = secondary_[i].value->FindFirstMap();
1225 // Map can be NULL, if the stub is constant function call
1226 // with a primitive receiver.
1227 if (map == NULL) continue;
1228
1229 // Lookup in primary table and skip duplicates.
1230 int primary_offset = PrimaryOffset(name, flags, map);
1231 Entry* primary_entry = entry(primary_, primary_offset);
1232 if (primary_entry->key == name) {
1233 Map* primary_map = primary_entry->value->FindFirstMap();
1234 if (map == primary_map) continue;
1235 }
1236
1237 // Lookup in secondary table and add matches.
1238 int offset = SecondaryOffset(name, flags, primary_offset);
1239 if (entry(secondary_, offset) == &secondary_[i]) {
1240 types->Add(Handle<Map>(map));
1241 }
1242 }
1243 }
1244}
1245
1246
Steve Blocka7e24c12009-10-30 11:49:00 +00001247// ------------------------------------------------------------------------
1248// StubCompiler implementation.
1249
1250
John Reck59135872010-11-02 12:39:01 -07001251MaybeObject* LoadCallbackProperty(Arguments args) {
Steve Blockd0582a62009-12-15 09:54:21 +00001252 ASSERT(args[0]->IsJSObject());
1253 ASSERT(args[1]->IsJSObject());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001254 AccessorInfo* callback = AccessorInfo::cast(args[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001255 Address getter_address = v8::ToCData<Address>(callback->getter());
1256 v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
1257 ASSERT(fun != NULL);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001258 v8::AccessorInfo info(&args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001259 HandleScope scope;
1260 v8::Handle<v8::Value> result;
1261 {
1262 // Leaving JavaScript.
1263 VMState state(EXTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001264 ExternalCallbackScope call_scope(getter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001265 result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
1266 }
1267 RETURN_IF_SCHEDULED_EXCEPTION();
1268 if (result.IsEmpty()) return Heap::undefined_value();
1269 return *v8::Utils::OpenHandle(*result);
1270}
1271
1272
John Reck59135872010-11-02 12:39:01 -07001273MaybeObject* StoreCallbackProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001274 JSObject* recv = JSObject::cast(args[0]);
1275 AccessorInfo* callback = AccessorInfo::cast(args[1]);
1276 Address setter_address = v8::ToCData<Address>(callback->setter());
1277 v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
1278 ASSERT(fun != NULL);
1279 Handle<String> name = args.at<String>(2);
1280 Handle<Object> value = args.at<Object>(3);
1281 HandleScope scope;
1282 LOG(ApiNamedPropertyAccess("store", recv, *name));
1283 CustomArguments custom_args(callback->data(), recv, recv);
1284 v8::AccessorInfo info(custom_args.end());
1285 {
1286 // Leaving JavaScript.
1287 VMState state(EXTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001288 ExternalCallbackScope call_scope(setter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001289 fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
1290 }
1291 RETURN_IF_SCHEDULED_EXCEPTION();
1292 return *value;
1293}
1294
Steve Block6ded16b2010-05-10 14:33:55 +01001295
1296static const int kAccessorInfoOffsetInInterceptorArgs = 2;
1297
1298
Steve Blocka7e24c12009-10-30 11:49:00 +00001299/**
1300 * Attempts to load a property with an interceptor (which must be present),
1301 * but doesn't search the prototype chain.
1302 *
1303 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
1304 * provide any value for the given name.
1305 */
John Reck59135872010-11-02 12:39:01 -07001306MaybeObject* LoadPropertyWithInterceptorOnly(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01001307 Handle<String> name_handle = args.at<String>(0);
1308 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
1309 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1310 ASSERT(args[2]->IsJSObject()); // Receiver.
1311 ASSERT(args[3]->IsJSObject()); // Holder.
1312 ASSERT(args.length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001313
1314 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1315 v8::NamedPropertyGetter getter =
1316 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1317 ASSERT(getter != NULL);
1318
1319 {
1320 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001321 v8::AccessorInfo info(args.arguments() -
1322 kAccessorInfoOffsetInInterceptorArgs);
Steve Blocka7e24c12009-10-30 11:49:00 +00001323 HandleScope scope;
1324 v8::Handle<v8::Value> r;
1325 {
1326 // Leaving JavaScript.
1327 VMState state(EXTERNAL);
1328 r = getter(v8::Utils::ToLocal(name_handle), info);
1329 }
1330 RETURN_IF_SCHEDULED_EXCEPTION();
1331 if (!r.IsEmpty()) {
1332 return *v8::Utils::OpenHandle(*r);
1333 }
1334 }
1335
1336 return Heap::no_interceptor_result_sentinel();
1337}
1338
1339
John Reck59135872010-11-02 12:39:01 -07001340static MaybeObject* ThrowReferenceError(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001341 // If the load is non-contextual, just return the undefined result.
1342 // Note that both keyed and non-keyed loads may end up here, so we
1343 // can't use either LoadIC or KeyedLoadIC constructors.
1344 IC ic(IC::NO_EXTRA_FRAME);
1345 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
Leon Clarkee46be812010-01-19 14:06:41 +00001346 if (!ic.SlowIsContextual()) return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001347
1348 // Throw a reference error.
1349 HandleScope scope;
1350 Handle<String> name_handle(name);
1351 Handle<Object> error =
1352 Factory::NewReferenceError("not_defined",
1353 HandleVector(&name_handle, 1));
1354 return Top::Throw(*error);
1355}
1356
1357
John Reck59135872010-11-02 12:39:01 -07001358static MaybeObject* LoadWithInterceptor(Arguments* args,
1359 PropertyAttributes* attrs) {
Steve Block6ded16b2010-05-10 14:33:55 +01001360 Handle<String> name_handle = args->at<String>(0);
1361 Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
1362 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1363 Handle<JSObject> receiver_handle = args->at<JSObject>(2);
1364 Handle<JSObject> holder_handle = args->at<JSObject>(3);
1365 ASSERT(args->length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001366
1367 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1368 v8::NamedPropertyGetter getter =
1369 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1370 ASSERT(getter != NULL);
1371
1372 {
1373 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001374 v8::AccessorInfo info(args->arguments() -
1375 kAccessorInfoOffsetInInterceptorArgs);
Steve Blocka7e24c12009-10-30 11:49:00 +00001376 HandleScope scope;
1377 v8::Handle<v8::Value> r;
1378 {
1379 // Leaving JavaScript.
1380 VMState state(EXTERNAL);
1381 r = getter(v8::Utils::ToLocal(name_handle), info);
1382 }
1383 RETURN_IF_SCHEDULED_EXCEPTION();
1384 if (!r.IsEmpty()) {
1385 *attrs = NONE;
1386 return *v8::Utils::OpenHandle(*r);
1387 }
1388 }
1389
John Reck59135872010-11-02 12:39:01 -07001390 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00001391 *receiver_handle,
1392 *name_handle,
1393 attrs);
1394 RETURN_IF_SCHEDULED_EXCEPTION();
1395 return result;
1396}
1397
1398
1399/**
1400 * Loads a property with an interceptor performing post interceptor
1401 * lookup if interceptor failed.
1402 */
John Reck59135872010-11-02 12:39:01 -07001403MaybeObject* LoadPropertyWithInterceptorForLoad(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001404 PropertyAttributes attr = NONE;
John Reck59135872010-11-02 12:39:01 -07001405 Object* result;
1406 { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
1407 if (!maybe_result->ToObject(&result)) return maybe_result;
1408 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001409
1410 // If the property is present, return it.
1411 if (attr != ABSENT) return result;
Steve Block6ded16b2010-05-10 14:33:55 +01001412 return ThrowReferenceError(String::cast(args[0]));
Steve Blocka7e24c12009-10-30 11:49:00 +00001413}
1414
1415
John Reck59135872010-11-02 12:39:01 -07001416MaybeObject* LoadPropertyWithInterceptorForCall(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001417 PropertyAttributes attr;
John Reck59135872010-11-02 12:39:01 -07001418 MaybeObject* result = LoadWithInterceptor(&args, &attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001419 RETURN_IF_SCHEDULED_EXCEPTION();
1420 // This is call IC. In this case, we simply return the undefined result which
1421 // will lead to an exception when trying to invoke the result as a
1422 // function.
1423 return result;
1424}
1425
1426
John Reck59135872010-11-02 12:39:01 -07001427MaybeObject* StoreInterceptorProperty(Arguments args) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001428 ASSERT(args.length() == 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001429 JSObject* recv = JSObject::cast(args[0]);
1430 String* name = String::cast(args[1]);
1431 Object* value = args[2];
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001432 StrictModeFlag strict_mode =
1433 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1434 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001435 ASSERT(recv->HasNamedInterceptor());
1436 PropertyAttributes attr = NONE;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001437 MaybeObject* result = recv->SetPropertyWithInterceptor(
1438 name, value, attr, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001439 return result;
1440}
1441
1442
John Reck59135872010-11-02 12:39:01 -07001443MaybeObject* KeyedLoadPropertyWithInterceptor(Arguments args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001444 JSObject* receiver = JSObject::cast(args[0]);
Ben Murdochf87a2032010-10-22 12:50:53 +01001445 ASSERT(Smi::cast(args[1])->value() >= 0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001446 uint32_t index = Smi::cast(args[1])->value();
1447 return receiver->GetElementWithInterceptor(receiver, index);
1448}
1449
1450
John Reck59135872010-11-02 12:39:01 -07001451MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001452 HandleScope scope;
1453 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001454 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1455 if (kind == Code::CALL_IC) {
1456 CallIC::GenerateInitialize(masm(), argc);
1457 } else {
1458 KeyedCallIC::GenerateInitialize(masm(), argc);
1459 }
John Reck59135872010-11-02 12:39:01 -07001460 Object* result;
1461 { MaybeObject* maybe_result =
1462 GetCodeWithFlags(flags, "CompileCallInitialize");
1463 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001464 }
John Reck59135872010-11-02 12:39:01 -07001465 Counters::call_initialize_stubs.Increment();
1466 Code* code = Code::cast(result);
1467 USE(code);
1468 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
1469 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001470 GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001471 return result;
1472}
1473
1474
John Reck59135872010-11-02 12:39:01 -07001475MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001476 HandleScope scope;
1477 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1478 // The code of the PreMonomorphic stub is the same as the code
1479 // of the Initialized stub. They just differ on the code object flags.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001480 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1481 if (kind == Code::CALL_IC) {
1482 CallIC::GenerateInitialize(masm(), argc);
1483 } else {
1484 KeyedCallIC::GenerateInitialize(masm(), argc);
1485 }
John Reck59135872010-11-02 12:39:01 -07001486 Object* result;
1487 { MaybeObject* maybe_result =
1488 GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1489 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001490 }
John Reck59135872010-11-02 12:39:01 -07001491 Counters::call_premonomorphic_stubs.Increment();
1492 Code* code = Code::cast(result);
1493 USE(code);
1494 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
1495 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001496 GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001497 return result;
1498}
1499
1500
John Reck59135872010-11-02 12:39:01 -07001501MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001502 HandleScope scope;
1503 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001504 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1505 if (kind == Code::CALL_IC) {
1506 CallIC::GenerateNormal(masm(), argc);
1507 } else {
1508 KeyedCallIC::GenerateNormal(masm(), argc);
1509 }
John Reck59135872010-11-02 12:39:01 -07001510 Object* result;
1511 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallNormal");
1512 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001513 }
John Reck59135872010-11-02 12:39:01 -07001514 Counters::call_normal_stubs.Increment();
1515 Code* code = Code::cast(result);
1516 USE(code);
1517 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
1518 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001519 GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001520 return result;
1521}
1522
1523
John Reck59135872010-11-02 12:39:01 -07001524MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001525 HandleScope scope;
1526 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001527 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1528 if (kind == Code::CALL_IC) {
1529 CallIC::GenerateMegamorphic(masm(), argc);
1530 } else {
1531 KeyedCallIC::GenerateMegamorphic(masm(), argc);
1532 }
1533
John Reck59135872010-11-02 12:39:01 -07001534 Object* result;
1535 { MaybeObject* maybe_result =
1536 GetCodeWithFlags(flags, "CompileCallMegamorphic");
1537 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001538 }
John Reck59135872010-11-02 12:39:01 -07001539 Counters::call_megamorphic_stubs.Increment();
1540 Code* code = Code::cast(result);
1541 USE(code);
1542 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
1543 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001544 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001545 return result;
1546}
1547
1548
John Reck59135872010-11-02 12:39:01 -07001549MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001550 HandleScope scope;
1551 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001552 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1553 if (kind == Code::CALL_IC) {
1554 CallIC::GenerateMiss(masm(), argc);
1555 } else {
1556 KeyedCallIC::GenerateMiss(masm(), argc);
1557 }
John Reck59135872010-11-02 12:39:01 -07001558 Object* result;
1559 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallMiss");
1560 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001561 }
John Reck59135872010-11-02 12:39:01 -07001562 Counters::call_megamorphic_stubs.Increment();
1563 Code* code = Code::cast(result);
1564 USE(code);
1565 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
1566 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001567 GDBJIT(AddCode(GDBJITInterface::CALL_MISS, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001568 return result;
1569}
1570
1571
1572#ifdef ENABLE_DEBUGGER_SUPPORT
John Reck59135872010-11-02 12:39:01 -07001573MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001574 HandleScope scope;
1575 Debug::GenerateCallICDebugBreak(masm());
John Reck59135872010-11-02 12:39:01 -07001576 Object* result;
1577 { MaybeObject* maybe_result =
1578 GetCodeWithFlags(flags, "CompileCallDebugBreak");
1579 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001580 }
John Reck59135872010-11-02 12:39:01 -07001581 Code* code = Code::cast(result);
1582 USE(code);
1583 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1584 USE(kind);
1585 PROFILE(CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
1586 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001587 return result;
1588}
1589
1590
John Reck59135872010-11-02 12:39:01 -07001591MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001592 HandleScope scope;
1593 // Use the same code for the the step in preparations as we do for
1594 // the miss case.
1595 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001596 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1597 if (kind == Code::CALL_IC) {
1598 CallIC::GenerateMiss(masm(), argc);
1599 } else {
1600 KeyedCallIC::GenerateMiss(masm(), argc);
1601 }
John Reck59135872010-11-02 12:39:01 -07001602 Object* result;
1603 { MaybeObject* maybe_result =
1604 GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1605 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001606 }
John Reck59135872010-11-02 12:39:01 -07001607 Code* code = Code::cast(result);
1608 USE(code);
1609 PROFILE(CodeCreateEvent(
1610 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1611 code,
1612 code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001613 return result;
1614}
1615#endif
1616
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001617#undef CALL_LOGGER_TAG
Steve Blocka7e24c12009-10-30 11:49:00 +00001618
John Reck59135872010-11-02 12:39:01 -07001619MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags,
1620 const char* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001621 // Check for allocation failures during stub compilation.
1622 if (failure_->IsFailure()) return failure_;
1623
1624 // Create code object in the heap.
1625 CodeDesc desc;
1626 masm_.GetCode(&desc);
John Reck59135872010-11-02 12:39:01 -07001627 MaybeObject* result = Heap::CreateCode(desc, flags, masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +00001628#ifdef ENABLE_DISASSEMBLER
1629 if (FLAG_print_code_stubs && !result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001630 Code::cast(result->ToObjectUnchecked())->Disassemble(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001631 }
1632#endif
1633 return result;
1634}
1635
1636
John Reck59135872010-11-02 12:39:01 -07001637MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001638 if (FLAG_print_code_stubs && (name != NULL)) {
1639 return GetCodeWithFlags(flags, *name->ToCString());
1640 }
1641 return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1642}
1643
Andrei Popescu402d9372010-02-26 13:31:12 +00001644
Leon Clarke4515c472010-02-03 11:58:03 +00001645void StubCompiler::LookupPostInterceptor(JSObject* holder,
1646 String* name,
1647 LookupResult* lookup) {
1648 holder->LocalLookupRealNamedProperty(name, lookup);
Andrei Popescu402d9372010-02-26 13:31:12 +00001649 if (!lookup->IsProperty()) {
1650 lookup->NotFound();
Leon Clarke4515c472010-02-03 11:58:03 +00001651 Object* proto = holder->GetPrototype();
1652 if (proto != Heap::null_value()) {
1653 proto->Lookup(name, lookup);
1654 }
1655 }
1656}
1657
1658
Steve Blocka7e24c12009-10-30 11:49:00 +00001659
John Reck59135872010-11-02 12:39:01 -07001660MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001661 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
John Reck59135872010-11-02 12:39:01 -07001662 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001663 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001664 PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG,
1665 Code::cast(result->ToObjectUnchecked()),
1666 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001667 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1668 name,
1669 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001670 }
1671 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001672}
1673
1674
John Reck59135872010-11-02 12:39:01 -07001675MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001676 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
John Reck59135872010-11-02 12:39:01 -07001677 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001678 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001679 PROFILE(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
1680 Code::cast(result->ToObjectUnchecked()),
1681 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001682 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1683 name,
1684 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001685 }
1686 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001687}
1688
1689
John Reck59135872010-11-02 12:39:01 -07001690MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001691 Code::Flags flags = Code::ComputeMonomorphicFlags(
1692 Code::STORE_IC, type, strict_mode_);
John Reck59135872010-11-02 12:39:01 -07001693 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001694 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001695 PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG,
1696 Code::cast(result->ToObjectUnchecked()),
1697 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001698 GDBJIT(AddCode(GDBJITInterface::STORE_IC,
1699 name,
1700 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001701 }
1702 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001703}
1704
1705
John Reck59135872010-11-02 12:39:01 -07001706MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001707 Code::Flags flags = Code::ComputeMonomorphicFlags(
1708 Code::KEYED_STORE_IC, type, strict_mode_);
John Reck59135872010-11-02 12:39:01 -07001709 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001710 if (!result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001711 PROFILE(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
1712 Code::cast(result->ToObjectUnchecked()),
1713 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001714 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC,
1715 name,
1716 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001717 }
1718 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001719}
1720
1721
Steve Block8defd9f2010-07-08 12:39:36 +01001722CallStubCompiler::CallStubCompiler(int argc,
1723 InLoopFlag in_loop,
1724 Code::Kind kind,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001725 Code::ExtraICState extra_ic_state,
Steve Block8defd9f2010-07-08 12:39:36 +01001726 InlineCacheHolderFlag cache_holder)
Ben Murdochb8e0da22011-05-16 14:20:40 +01001727 : arguments_(argc),
1728 in_loop_(in_loop),
1729 kind_(kind),
1730 extra_ic_state_(extra_ic_state),
1731 cache_holder_(cache_holder) {
Steve Block8defd9f2010-07-08 12:39:36 +01001732}
1733
1734
Ben Murdochb0fe1622011-05-05 13:52:32 +01001735bool CallStubCompiler::HasCustomCallGenerator(BuiltinFunctionId id) {
1736#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
1737 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1738#undef CALL_GENERATOR_CASE
1739 return false;
1740}
1741
1742
1743MaybeObject* CallStubCompiler::CompileCustomCall(BuiltinFunctionId id,
John Reck59135872010-11-02 12:39:01 -07001744 Object* object,
1745 JSObject* holder,
1746 JSGlobalPropertyCell* cell,
1747 JSFunction* function,
1748 String* fname) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001749#define CALL_GENERATOR_CASE(name) \
1750 if (id == k##name) { \
1751 return CallStubCompiler::Compile##name##Call(object, \
1752 holder, \
1753 cell, \
1754 function, \
1755 fname); \
Steve Block59151502010-09-22 15:07:15 +01001756 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001757 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1758#undef CALL_GENERATOR_CASE
1759 ASSERT(!HasCustomCallGenerator(id));
Steve Block59151502010-09-22 15:07:15 +01001760 return Heap::undefined_value();
Kristian Monsen25f61362010-05-21 11:50:48 +01001761}
1762
1763
John Reck59135872010-11-02 12:39:01 -07001764MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001765 int argc = arguments_.immediate();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001766 Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001767 type,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001768 extra_ic_state_,
Steve Block8defd9f2010-07-08 12:39:36 +01001769 cache_holder_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001770 in_loop_,
1771 argc);
1772 return GetCodeWithFlags(flags, name);
1773}
1774
1775
John Reck59135872010-11-02 12:39:01 -07001776MaybeObject* CallStubCompiler::GetCode(JSFunction* function) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001777 String* function_name = NULL;
1778 if (function->shared()->name()->IsString()) {
1779 function_name = String::cast(function->shared()->name());
1780 }
1781 return GetCode(CONSTANT_FUNCTION, function_name);
1782}
1783
1784
John Reck59135872010-11-02 12:39:01 -07001785MaybeObject* ConstructStubCompiler::GetCode() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001786 Code::Flags flags = Code::ComputeFlags(Code::STUB);
John Reck59135872010-11-02 12:39:01 -07001787 Object* result;
1788 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ConstructStub");
1789 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001790 }
John Reck59135872010-11-02 12:39:01 -07001791 Code* code = Code::cast(result);
1792 USE(code);
1793 PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001794 GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001795 return result;
1796}
1797
1798
Steve Block6ded16b2010-05-10 14:33:55 +01001799CallOptimization::CallOptimization(LookupResult* lookup) {
1800 if (!lookup->IsProperty() || !lookup->IsCacheable() ||
1801 lookup->type() != CONSTANT_FUNCTION) {
1802 Initialize(NULL);
1803 } else {
1804 // We only optimize constant function calls.
1805 Initialize(lookup->GetConstantFunction());
1806 }
1807}
1808
1809CallOptimization::CallOptimization(JSFunction* function) {
1810 Initialize(function);
1811}
1812
1813
1814int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
1815 JSObject* holder) const {
1816 ASSERT(is_simple_api_call_);
1817 if (expected_receiver_type_ == NULL) return 0;
1818 int depth = 0;
1819 while (object != holder) {
1820 if (object->IsInstanceOf(expected_receiver_type_)) return depth;
1821 object = JSObject::cast(object->GetPrototype());
1822 ++depth;
1823 }
1824 if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
1825 return kInvalidProtoDepth;
1826}
1827
1828
1829void CallOptimization::Initialize(JSFunction* function) {
1830 constant_function_ = NULL;
1831 is_simple_api_call_ = false;
1832 expected_receiver_type_ = NULL;
1833 api_call_info_ = NULL;
1834
1835 if (function == NULL || !function->is_compiled()) return;
1836
1837 constant_function_ = function;
1838 AnalyzePossibleApiFunction(function);
1839}
1840
1841
1842void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
1843 SharedFunctionInfo* sfi = function->shared();
1844 if (!sfi->IsApiFunction()) return;
1845 FunctionTemplateInfo* info = sfi->get_api_func_data();
1846
1847 // Require a C++ callback.
1848 if (info->call_code()->IsUndefined()) return;
1849 api_call_info_ = CallHandlerInfo::cast(info->call_code());
1850
1851 // Accept signatures that either have no restrictions at all or
1852 // only have restrictions on the receiver.
1853 if (!info->signature()->IsUndefined()) {
1854 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1855 if (!signature->args()->IsUndefined()) return;
1856 if (!signature->receiver()->IsUndefined()) {
1857 expected_receiver_type_ =
1858 FunctionTemplateInfo::cast(signature->receiver());
1859 }
1860 }
1861
1862 is_simple_api_call_ = true;
1863}
1864
1865
Steve Block1e0659c2011-05-24 12:43:12 +01001866MaybeObject* ExternalArrayStubCompiler::GetCode(Code::Flags flags) {
1867 Object* result;
1868 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ExternalArrayStub");
1869 if (!maybe_result->ToObject(&result)) return maybe_result;
1870 }
1871 Code* code = Code::cast(result);
1872 USE(code);
1873 PROFILE(CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayStub"));
1874 return result;
1875}
1876
1877
Steve Blocka7e24c12009-10-30 11:49:00 +00001878} } // namespace v8::internal