blob: 0c6a7f7438de5136f0fd7e437b7a4fd665efc7cf [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
Steve Block44f0eee2011-05-26 01:26:41 +010044StubCache::StubCache(Isolate* isolate) : isolate_(isolate) {
45 ASSERT(isolate == Isolate::Current());
46 memset(primary_, 0, sizeof(primary_[0]) * StubCache::kPrimaryTableSize);
47 memset(secondary_, 0, sizeof(secondary_[0]) * StubCache::kSecondaryTableSize);
48}
49
Steve Blocka7e24c12009-10-30 11:49:00 +000050
51void StubCache::Initialize(bool create_heap_objects) {
52 ASSERT(IsPowerOf2(kPrimaryTableSize));
53 ASSERT(IsPowerOf2(kSecondaryTableSize));
54 if (create_heap_objects) {
55 HandleScope scope;
56 Clear();
57 }
58}
59
60
61Code* StubCache::Set(String* name, Map* map, Code* code) {
62 // Get the flags from the code.
63 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
64
65 // Validate that the name does not move on scavenge, and that we
66 // can use identity checks instead of string equality checks.
Steve Block44f0eee2011-05-26 01:26:41 +010067 ASSERT(!heap()->InNewSpace(name));
Steve Blocka7e24c12009-10-30 11:49:00 +000068 ASSERT(name->IsSymbol());
69
70 // The state bits are not important to the hash function because
71 // the stub cache only contains monomorphic stubs. Make sure that
72 // the bits are the least significant so they will be the ones
73 // masked out.
74 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
75 ASSERT(Code::kFlagsICStateShift == 0);
76
77 // Make sure that the code type is not included in the hash.
78 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
79
80 // Compute the primary entry.
81 int primary_offset = PrimaryOffset(name, flags, map);
82 Entry* primary = entry(primary_, primary_offset);
83 Code* hit = primary->value;
84
85 // If the primary entry has useful data in it, we retire it to the
86 // secondary cache before overwriting it.
Steve Block44f0eee2011-05-26 01:26:41 +010087 if (hit != isolate_->builtins()->builtin(Builtins::kIllegal)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000088 Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
89 int secondary_offset =
90 SecondaryOffset(primary->key, primary_flags, primary_offset);
91 Entry* secondary = entry(secondary_, secondary_offset);
92 *secondary = *primary;
93 }
94
95 // Update primary cache.
96 primary->key = name;
97 primary->value = code;
98 return code;
99}
100
101
John Reck59135872010-11-02 12:39:01 -0700102MaybeObject* StubCache::ComputeLoadNonexistent(String* name,
103 JSObject* receiver) {
Steve Block8defd9f2010-07-08 12:39:36 +0100104 ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
Steve Block6ded16b2010-05-10 14:33:55 +0100105 // If no global objects are present in the prototype chain, the load
106 // nonexistent IC stub can be shared for all names for a given map
107 // and we use the empty string for the map cache in that case. If
108 // there are global objects involved, we need to check global
109 // property cells in the stub and therefore the stub will be
110 // specific to the name.
Steve Block44f0eee2011-05-26 01:26:41 +0100111 String* cache_name = heap()->empty_string();
Steve Block6ded16b2010-05-10 14:33:55 +0100112 if (receiver->IsGlobalObject()) cache_name = name;
113 JSObject* last = receiver;
Steve Block44f0eee2011-05-26 01:26:41 +0100114 while (last->GetPrototype() != heap()->null_value()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100115 last = JSObject::cast(last->GetPrototype());
116 if (last->IsGlobalObject()) cache_name = name;
117 }
118 // Compile the stub that is either shared for all names or
119 // name specific if there are global objects involved.
120 Code::Flags flags =
121 Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
122 Object* code = receiver->map()->FindInCodeCache(cache_name, flags);
123 if (code->IsUndefined()) {
124 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700125 { MaybeObject* maybe_code =
126 compiler.CompileLoadNonexistent(cache_name, receiver, last);
127 if (!maybe_code->ToObject(&code)) return maybe_code;
128 }
Steve Block44f0eee2011-05-26 01:26:41 +0100129 PROFILE(isolate_,
130 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100131 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, cache_name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700132 Object* result;
133 { MaybeObject* maybe_result =
134 receiver->UpdateMapCodeCache(cache_name, Code::cast(code));
135 if (!maybe_result->ToObject(&result)) return maybe_result;
136 }
Steve Block6ded16b2010-05-10 14:33:55 +0100137 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100138 return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100139}
140
141
John Reck59135872010-11-02 12:39:01 -0700142MaybeObject* StubCache::ComputeLoadField(String* name,
143 JSObject* receiver,
144 JSObject* holder,
145 int field_index) {
Steve Block8defd9f2010-07-08 12:39:36 +0100146 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000147 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100148 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000149 if (code->IsUndefined()) {
150 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700151 { MaybeObject* maybe_code =
152 compiler.CompileLoadField(receiver, holder, field_index, name);
153 if (!maybe_code->ToObject(&code)) return maybe_code;
154 }
Steve Block44f0eee2011-05-26 01:26:41 +0100155 PROFILE(isolate_,
156 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100157 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700158 Object* result;
159 { MaybeObject* maybe_result =
160 receiver->UpdateMapCodeCache(name, Code::cast(code));
161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000163 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100164 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000165}
166
167
John Reck59135872010-11-02 12:39:01 -0700168MaybeObject* StubCache::ComputeLoadCallback(String* name,
169 JSObject* receiver,
170 JSObject* holder,
171 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000172 ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
Steve Block8defd9f2010-07-08 12:39:36 +0100173 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000174 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100175 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000176 if (code->IsUndefined()) {
177 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700178 { MaybeObject* maybe_code =
179 compiler.CompileLoadCallback(name, receiver, holder, callback);
180 if (!maybe_code->ToObject(&code)) return maybe_code;
181 }
Steve Block44f0eee2011-05-26 01:26:41 +0100182 PROFILE(isolate_,
183 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100184 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700185 Object* result;
186 { MaybeObject* maybe_result =
187 receiver->UpdateMapCodeCache(name, Code::cast(code));
188 if (!maybe_result->ToObject(&result)) return maybe_result;
189 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000190 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100191 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000192}
193
194
John Reck59135872010-11-02 12:39:01 -0700195MaybeObject* StubCache::ComputeLoadConstant(String* name,
196 JSObject* receiver,
197 JSObject* holder,
198 Object* value) {
Steve Block8defd9f2010-07-08 12:39:36 +0100199 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000200 Code::Flags flags =
201 Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100202 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000203 if (code->IsUndefined()) {
204 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700205 { MaybeObject* maybe_code =
206 compiler.CompileLoadConstant(receiver, holder, value, name);
207 if (!maybe_code->ToObject(&code)) return maybe_code;
208 }
Steve Block44f0eee2011-05-26 01:26:41 +0100209 PROFILE(isolate_,
210 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100211 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700212 Object* result;
213 { MaybeObject* maybe_result =
214 receiver->UpdateMapCodeCache(name, Code::cast(code));
215 if (!maybe_result->ToObject(&result)) return maybe_result;
216 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000217 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100218 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000219}
220
221
John Reck59135872010-11-02 12:39:01 -0700222MaybeObject* StubCache::ComputeLoadInterceptor(String* name,
223 JSObject* receiver,
224 JSObject* holder) {
Steve Block8defd9f2010-07-08 12:39:36 +0100225 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000226 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100227 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 if (code->IsUndefined()) {
229 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700230 { MaybeObject* maybe_code =
231 compiler.CompileLoadInterceptor(receiver, holder, name);
232 if (!maybe_code->ToObject(&code)) return maybe_code;
233 }
Steve Block44f0eee2011-05-26 01:26:41 +0100234 PROFILE(isolate_,
235 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100236 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700237 Object* result;
238 { MaybeObject* maybe_result =
239 receiver->UpdateMapCodeCache(name, Code::cast(code));
240 if (!maybe_result->ToObject(&result)) return maybe_result;
241 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000242 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100243 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000244}
245
246
John Reck59135872010-11-02 12:39:01 -0700247MaybeObject* StubCache::ComputeLoadNormal() {
Steve Block44f0eee2011-05-26 01:26:41 +0100248 return isolate_->builtins()->builtin(Builtins::kLoadIC_Normal);
Steve Blocka7e24c12009-10-30 11:49:00 +0000249}
250
251
John Reck59135872010-11-02 12:39:01 -0700252MaybeObject* StubCache::ComputeLoadGlobal(String* name,
253 JSObject* receiver,
254 GlobalObject* holder,
255 JSGlobalPropertyCell* cell,
256 bool is_dont_delete) {
Steve Block8defd9f2010-07-08 12:39:36 +0100257 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000258 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100259 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000260 if (code->IsUndefined()) {
261 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700262 { MaybeObject* maybe_code = compiler.CompileLoadGlobal(receiver,
263 holder,
264 cell,
265 name,
266 is_dont_delete);
267 if (!maybe_code->ToObject(&code)) return maybe_code;
268 }
Steve Block44f0eee2011-05-26 01:26:41 +0100269 PROFILE(isolate_,
270 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100271 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700272 Object* result;
273 { MaybeObject* maybe_result =
274 receiver->UpdateMapCodeCache(name, Code::cast(code));
275 if (!maybe_result->ToObject(&result)) return maybe_result;
276 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000277 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100278 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000279}
280
281
John Reck59135872010-11-02 12:39:01 -0700282MaybeObject* StubCache::ComputeKeyedLoadField(String* name,
283 JSObject* receiver,
284 JSObject* holder,
285 int field_index) {
Steve Block8defd9f2010-07-08 12:39:36 +0100286 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000287 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100288 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000289 if (code->IsUndefined()) {
290 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700291 { MaybeObject* maybe_code =
292 compiler.CompileLoadField(name, receiver, holder, field_index);
293 if (!maybe_code->ToObject(&code)) return maybe_code;
294 }
Steve Block44f0eee2011-05-26 01:26:41 +0100295 PROFILE(isolate_,
296 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100297 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700298 Object* result;
299 { MaybeObject* maybe_result =
300 receiver->UpdateMapCodeCache(name, Code::cast(code));
301 if (!maybe_result->ToObject(&result)) return maybe_result;
302 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000303 }
304 return code;
305}
306
307
John Reck59135872010-11-02 12:39:01 -0700308MaybeObject* StubCache::ComputeKeyedLoadConstant(String* name,
309 JSObject* receiver,
310 JSObject* holder,
311 Object* value) {
Steve Block8defd9f2010-07-08 12:39:36 +0100312 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000313 Code::Flags flags =
314 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100315 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000316 if (code->IsUndefined()) {
317 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700318 { MaybeObject* maybe_code =
319 compiler.CompileLoadConstant(name, receiver, holder, value);
320 if (!maybe_code->ToObject(&code)) return maybe_code;
321 }
Steve Block44f0eee2011-05-26 01:26:41 +0100322 PROFILE(isolate_,
323 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100324 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700325 Object* result;
326 { MaybeObject* maybe_result =
327 receiver->UpdateMapCodeCache(name, Code::cast(code));
328 if (!maybe_result->ToObject(&result)) return maybe_result;
329 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000330 }
331 return code;
332}
333
334
John Reck59135872010-11-02 12:39:01 -0700335MaybeObject* StubCache::ComputeKeyedLoadInterceptor(String* name,
336 JSObject* receiver,
337 JSObject* holder) {
Steve Block8defd9f2010-07-08 12:39:36 +0100338 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000339 Code::Flags flags =
340 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100341 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000342 if (code->IsUndefined()) {
343 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700344 { MaybeObject* maybe_code =
345 compiler.CompileLoadInterceptor(receiver, holder, name);
346 if (!maybe_code->ToObject(&code)) return maybe_code;
347 }
Steve Block44f0eee2011-05-26 01:26:41 +0100348 PROFILE(isolate_,
349 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100350 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700351 Object* result;
352 { MaybeObject* maybe_result =
353 receiver->UpdateMapCodeCache(name, Code::cast(code));
354 if (!maybe_result->ToObject(&result)) return maybe_result;
355 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000356 }
357 return code;
358}
359
360
John Reck59135872010-11-02 12:39:01 -0700361MaybeObject* StubCache::ComputeKeyedLoadCallback(String* name,
362 JSObject* receiver,
363 JSObject* holder,
364 AccessorInfo* callback) {
Steve Block8defd9f2010-07-08 12:39:36 +0100365 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000366 Code::Flags flags =
367 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100368 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000369 if (code->IsUndefined()) {
370 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700371 { MaybeObject* maybe_code =
372 compiler.CompileLoadCallback(name, receiver, holder, callback);
373 if (!maybe_code->ToObject(&code)) return maybe_code;
374 }
Steve Block44f0eee2011-05-26 01:26:41 +0100375 PROFILE(isolate_,
376 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100377 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700378 Object* result;
379 { MaybeObject* maybe_result =
380 receiver->UpdateMapCodeCache(name, Code::cast(code));
381 if (!maybe_result->ToObject(&result)) return maybe_result;
382 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000383 }
384 return code;
385}
386
387
388
John Reck59135872010-11-02 12:39:01 -0700389MaybeObject* StubCache::ComputeKeyedLoadArrayLength(String* name,
390 JSArray* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000391 Code::Flags flags =
392 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Steve Block8defd9f2010-07-08 12:39:36 +0100393 ASSERT(receiver->IsJSObject());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100394 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000395 if (code->IsUndefined()) {
396 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700397 { MaybeObject* maybe_code = compiler.CompileLoadArrayLength(name);
398 if (!maybe_code->ToObject(&code)) return maybe_code;
399 }
Steve Block44f0eee2011-05-26 01:26:41 +0100400 PROFILE(isolate_,
401 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100402 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700403 Object* result;
404 { MaybeObject* maybe_result =
405 receiver->UpdateMapCodeCache(name, Code::cast(code));
406 if (!maybe_result->ToObject(&result)) return maybe_result;
407 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000408 }
409 return code;
410}
411
412
John Reck59135872010-11-02 12:39:01 -0700413MaybeObject* StubCache::ComputeKeyedLoadStringLength(String* name,
414 String* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000415 Code::Flags flags =
416 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Steve Block8defd9f2010-07-08 12:39:36 +0100417 Map* map = receiver->map();
418 Object* code = map->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000419 if (code->IsUndefined()) {
420 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700421 { MaybeObject* maybe_code = compiler.CompileLoadStringLength(name);
422 if (!maybe_code->ToObject(&code)) return maybe_code;
423 }
Steve Block44f0eee2011-05-26 01:26:41 +0100424 PROFILE(isolate_,
425 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100426 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700427 Object* result;
428 { MaybeObject* maybe_result = map->UpdateCodeCache(name, Code::cast(code));
429 if (!maybe_result->ToObject(&result)) return maybe_result;
430 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000431 }
432 return code;
433}
434
435
John Reck59135872010-11-02 12:39:01 -0700436MaybeObject* StubCache::ComputeKeyedLoadFunctionPrototype(
437 String* name,
438 JSFunction* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000439 Code::Flags flags =
440 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100441 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000442 if (code->IsUndefined()) {
443 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700444 { MaybeObject* maybe_code = compiler.CompileLoadFunctionPrototype(name);
445 if (!maybe_code->ToObject(&code)) return maybe_code;
446 }
Steve Block44f0eee2011-05-26 01:26:41 +0100447 PROFILE(isolate_,
448 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100449 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700450 Object* result;
451 { MaybeObject* maybe_result =
452 receiver->UpdateMapCodeCache(name, Code::cast(code));
453 if (!maybe_result->ToObject(&result)) return maybe_result;
454 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000455 }
456 return code;
457}
458
459
Ben Murdochb0fe1622011-05-05 13:52:32 +0100460MaybeObject* StubCache::ComputeKeyedLoadSpecialized(JSObject* receiver) {
Steve Block1e0659c2011-05-24 12:43:12 +0100461 // Using NORMAL as the PropertyType for array element loads is a misuse. The
462 // generated stub always accesses fast elements, not slow-mode fields, but
463 // some property type is required for the stub lookup. Note that overloading
464 // the NORMAL PropertyType is only safe as long as no stubs are generated for
465 // other keyed field loads. This is guaranteed to be the case since all field
466 // keyed loads that are not array elements go through a generic builtin stub.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100467 Code::Flags flags =
468 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, NORMAL);
Steve Block44f0eee2011-05-26 01:26:41 +0100469 String* name = heap()->KeyedLoadSpecialized_symbol();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100470 Object* code = receiver->map()->FindInCodeCache(name, flags);
471 if (code->IsUndefined()) {
472 KeyedLoadStubCompiler compiler;
473 { MaybeObject* maybe_code = compiler.CompileLoadSpecialized(receiver);
474 if (!maybe_code->ToObject(&code)) return maybe_code;
475 }
Steve Block44f0eee2011-05-26 01:26:41 +0100476 PROFILE(isolate_,
477 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
Steve Block1e0659c2011-05-24 12:43:12 +0100478 Object* result;
479 { MaybeObject* maybe_result =
480 receiver->UpdateMapCodeCache(name, Code::cast(code));
481 if (!maybe_result->ToObject(&result)) return maybe_result;
482 }
483 }
484 return code;
485}
486
487
John Reck59135872010-11-02 12:39:01 -0700488MaybeObject* StubCache::ComputeStoreField(String* name,
489 JSObject* receiver,
490 int field_index,
Steve Block1e0659c2011-05-24 12:43:12 +0100491 Map* transition,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100492 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000493 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
Steve Block1e0659c2011-05-24 12:43:12 +0100494 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100495 Code::STORE_IC, type, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000496 Object* code = receiver->map()->FindInCodeCache(name, flags);
497 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100498 StoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700499 { MaybeObject* maybe_code =
500 compiler.CompileStoreField(receiver, field_index, transition, name);
501 if (!maybe_code->ToObject(&code)) return maybe_code;
502 }
Steve Block44f0eee2011-05-26 01:26:41 +0100503 PROFILE(isolate_,
504 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100505 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700506 Object* result;
507 { MaybeObject* maybe_result =
508 receiver->UpdateMapCodeCache(name, Code::cast(code));
509 if (!maybe_result->ToObject(&result)) return maybe_result;
510 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000511 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100512 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000513}
514
515
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100516MaybeObject* StubCache::ComputeKeyedStoreSpecialized(
517 JSObject* receiver,
518 StrictModeFlag strict_mode) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100519 Code::Flags flags =
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100520 Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL, strict_mode);
Steve Block44f0eee2011-05-26 01:26:41 +0100521 String* name = heap()->KeyedStoreSpecialized_symbol();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100522 Object* code = receiver->map()->FindInCodeCache(name, flags);
523 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100524 KeyedStoreStubCompiler compiler(strict_mode);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100525 { MaybeObject* maybe_code = compiler.CompileStoreSpecialized(receiver);
526 if (!maybe_code->ToObject(&code)) return maybe_code;
527 }
Steve Block44f0eee2011-05-26 01:26:41 +0100528 PROFILE(isolate_,
529 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100530 Object* result;
531 { MaybeObject* maybe_result =
532 receiver->UpdateMapCodeCache(name, Code::cast(code));
533 if (!maybe_result->ToObject(&result)) return maybe_result;
534 }
535 }
536 return code;
537}
538
539
Steve Block1e0659c2011-05-24 12:43:12 +0100540namespace {
541
542ExternalArrayType ElementsKindToExternalArrayType(JSObject::ElementsKind kind) {
543 switch (kind) {
544 case JSObject::EXTERNAL_BYTE_ELEMENTS:
545 return kExternalByteArray;
546 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
547 return kExternalUnsignedByteArray;
548 case JSObject::EXTERNAL_SHORT_ELEMENTS:
549 return kExternalShortArray;
550 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
551 return kExternalUnsignedShortArray;
552 case JSObject::EXTERNAL_INT_ELEMENTS:
553 return kExternalIntArray;
554 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
555 return kExternalUnsignedIntArray;
556 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
557 return kExternalFloatArray;
Steve Block44f0eee2011-05-26 01:26:41 +0100558 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
559 return kExternalPixelArray;
Steve Block1e0659c2011-05-24 12:43:12 +0100560 default:
561 UNREACHABLE();
562 return static_cast<ExternalArrayType>(0);
563 }
564}
565
Steve Block44f0eee2011-05-26 01:26:41 +0100566String* ExternalArrayTypeToStubName(Heap* heap,
567 ExternalArrayType array_type,
568 bool is_store) {
569 if (is_store) {
570 switch (array_type) {
571 case kExternalByteArray:
572 return heap->KeyedStoreExternalByteArray_symbol();
573 case kExternalUnsignedByteArray:
574 return heap->KeyedStoreExternalUnsignedByteArray_symbol();
575 case kExternalShortArray:
576 return heap->KeyedStoreExternalShortArray_symbol();
577 case kExternalUnsignedShortArray:
578 return heap->KeyedStoreExternalUnsignedShortArray_symbol();
579 case kExternalIntArray:
580 return heap->KeyedStoreExternalIntArray_symbol();
581 case kExternalUnsignedIntArray:
582 return heap->KeyedStoreExternalUnsignedIntArray_symbol();
583 case kExternalFloatArray:
584 return heap->KeyedStoreExternalFloatArray_symbol();
585 case kExternalPixelArray:
586 return heap->KeyedStoreExternalPixelArray_symbol();
587 default:
588 UNREACHABLE();
589 return NULL;
590 }
591 } else {
592 switch (array_type) {
593 case kExternalByteArray:
594 return heap->KeyedLoadExternalByteArray_symbol();
595 case kExternalUnsignedByteArray:
596 return heap->KeyedLoadExternalUnsignedByteArray_symbol();
597 case kExternalShortArray:
598 return heap->KeyedLoadExternalShortArray_symbol();
599 case kExternalUnsignedShortArray:
600 return heap->KeyedLoadExternalUnsignedShortArray_symbol();
601 case kExternalIntArray:
602 return heap->KeyedLoadExternalIntArray_symbol();
603 case kExternalUnsignedIntArray:
604 return heap->KeyedLoadExternalUnsignedIntArray_symbol();
605 case kExternalFloatArray:
606 return heap->KeyedLoadExternalFloatArray_symbol();
607 case kExternalPixelArray:
608 return heap->KeyedLoadExternalPixelArray_symbol();
609 default:
610 UNREACHABLE();
611 return NULL;
612 }
613 }
614}
615
Steve Block1e0659c2011-05-24 12:43:12 +0100616} // anonymous namespace
617
618
619MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray(
620 JSObject* receiver,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100621 bool is_store,
622 StrictModeFlag strict_mode) {
Steve Block1e0659c2011-05-24 12:43:12 +0100623 Code::Flags flags =
624 Code::ComputeMonomorphicFlags(
Steve Block44f0eee2011-05-26 01:26:41 +0100625 is_store ? Code::KEYED_EXTERNAL_ARRAY_STORE_IC :
626 Code::KEYED_EXTERNAL_ARRAY_LOAD_IC,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100627 NORMAL,
628 strict_mode);
Steve Block1e0659c2011-05-24 12:43:12 +0100629 ExternalArrayType array_type =
630 ElementsKindToExternalArrayType(receiver->GetElementsKind());
Steve Block44f0eee2011-05-26 01:26:41 +0100631 String* name = ExternalArrayTypeToStubName(heap(), array_type, is_store);
632 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Block1e0659c2011-05-24 12:43:12 +0100633 if (code->IsUndefined()) {
634 ExternalArrayStubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +0100635 { MaybeObject* maybe_code =
636 is_store ?
637 compiler.CompileKeyedStoreStub(receiver, array_type, flags) :
638 compiler.CompileKeyedLoadStub(receiver, array_type, flags);
Steve Block1e0659c2011-05-24 12:43:12 +0100639 if (!maybe_code->ToObject(&code)) return maybe_code;
640 }
Steve Block44f0eee2011-05-26 01:26:41 +0100641 Code::cast(code)->set_external_array_type(array_type);
Steve Block1e0659c2011-05-24 12:43:12 +0100642 if (is_store) {
Steve Block44f0eee2011-05-26 01:26:41 +0100643 PROFILE(isolate_,
644 CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_STORE_IC_TAG,
645 Code::cast(code), 0));
Steve Block1e0659c2011-05-24 12:43:12 +0100646 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100647 PROFILE(isolate_,
648 CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG,
649 Code::cast(code), 0));
Steve Block1e0659c2011-05-24 12:43:12 +0100650 }
651 Object* result;
652 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +0100653 receiver->UpdateMapCodeCache(name, Code::cast(code));
Steve Block1e0659c2011-05-24 12:43:12 +0100654 if (!maybe_result->ToObject(&result)) return maybe_result;
655 }
656 }
657 return code;
658}
659
660
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100661MaybeObject* StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +0100662 return isolate_->builtins()->builtin((strict_mode == kStrictMode)
663 ? Builtins::kStoreIC_Normal_Strict
664 : Builtins::kStoreIC_Normal);
Steve Block8defd9f2010-07-08 12:39:36 +0100665}
666
667
John Reck59135872010-11-02 12:39:01 -0700668MaybeObject* StubCache::ComputeStoreGlobal(String* name,
669 GlobalObject* receiver,
Steve Block1e0659c2011-05-24 12:43:12 +0100670 JSGlobalPropertyCell* cell,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100671 StrictModeFlag strict_mode) {
Steve Block1e0659c2011-05-24 12:43:12 +0100672 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100673 Code::STORE_IC, NORMAL, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000674 Object* code = receiver->map()->FindInCodeCache(name, flags);
675 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100676 StoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700677 { MaybeObject* maybe_code =
678 compiler.CompileStoreGlobal(receiver, cell, name);
679 if (!maybe_code->ToObject(&code)) return maybe_code;
680 }
Steve Block44f0eee2011-05-26 01:26:41 +0100681 PROFILE(isolate_,
682 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100683 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700684 Object* result;
685 { MaybeObject* maybe_result =
686 receiver->UpdateMapCodeCache(name, Code::cast(code));
687 if (!maybe_result->ToObject(&result)) return maybe_result;
688 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000689 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100690 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000691}
692
693
Steve Block1e0659c2011-05-24 12:43:12 +0100694MaybeObject* StubCache::ComputeStoreCallback(
695 String* name,
696 JSObject* receiver,
697 AccessorInfo* callback,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100698 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000699 ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
Steve Block1e0659c2011-05-24 12:43:12 +0100700 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100701 Code::STORE_IC, CALLBACKS, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000702 Object* code = receiver->map()->FindInCodeCache(name, flags);
703 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100704 StoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700705 { MaybeObject* maybe_code =
706 compiler.CompileStoreCallback(receiver, callback, name);
707 if (!maybe_code->ToObject(&code)) return maybe_code;
708 }
Steve Block44f0eee2011-05-26 01:26:41 +0100709 PROFILE(isolate_,
710 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100711 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700712 Object* result;
713 { MaybeObject* maybe_result =
714 receiver->UpdateMapCodeCache(name, Code::cast(code));
715 if (!maybe_result->ToObject(&result)) return maybe_result;
716 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000717 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100718 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000719}
720
721
Steve Block1e0659c2011-05-24 12:43:12 +0100722MaybeObject* StubCache::ComputeStoreInterceptor(
723 String* name,
724 JSObject* receiver,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100725 StrictModeFlag strict_mode) {
Steve Block1e0659c2011-05-24 12:43:12 +0100726 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100727 Code::STORE_IC, INTERCEPTOR, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000728 Object* code = receiver->map()->FindInCodeCache(name, flags);
729 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100730 StoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700731 { MaybeObject* maybe_code =
732 compiler.CompileStoreInterceptor(receiver, name);
733 if (!maybe_code->ToObject(&code)) return maybe_code;
734 }
Steve Block44f0eee2011-05-26 01:26:41 +0100735 PROFILE(isolate_,
736 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100737 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700738 Object* result;
739 { MaybeObject* maybe_result =
740 receiver->UpdateMapCodeCache(name, Code::cast(code));
741 if (!maybe_result->ToObject(&result)) return maybe_result;
742 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000743 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100744 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000745}
746
747
John Reck59135872010-11-02 12:39:01 -0700748MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
749 JSObject* receiver,
750 int field_index,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100751 Map* transition,
752 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000753 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100754 Code::Flags flags = Code::ComputeMonomorphicFlags(
755 Code::KEYED_STORE_IC, type, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000756 Object* code = receiver->map()->FindInCodeCache(name, flags);
757 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100758 KeyedStoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700759 { MaybeObject* maybe_code =
760 compiler.CompileStoreField(receiver, field_index, transition, name);
761 if (!maybe_code->ToObject(&code)) return maybe_code;
762 }
Steve Block44f0eee2011-05-26 01:26:41 +0100763 PROFILE(isolate(),
764 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
765 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100766 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700767 Object* result;
768 { MaybeObject* maybe_result =
769 receiver->UpdateMapCodeCache(name, Code::cast(code));
770 if (!maybe_result->ToObject(&result)) return maybe_result;
771 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000772 }
773 return code;
774}
775
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100776#define CALL_LOGGER_TAG(kind, type) \
777 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
Steve Blocka7e24c12009-10-30 11:49:00 +0000778
John Reck59135872010-11-02 12:39:01 -0700779MaybeObject* StubCache::ComputeCallConstant(int argc,
780 InLoopFlag in_loop,
781 Code::Kind kind,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100782 Code::ExtraICState extra_ic_state,
John Reck59135872010-11-02 12:39:01 -0700783 String* name,
784 Object* object,
785 JSObject* holder,
786 JSFunction* function) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000787 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100788 InlineCacheHolderFlag cache_holder =
789 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100790 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000791
792 // Compute check type based on receiver/holder.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100793 CheckType check = RECEIVER_MAP_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000794 if (object->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100795 check = STRING_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000796 } else if (object->IsNumber()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100797 check = NUMBER_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000798 } else if (object->IsBoolean()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100799 check = BOOLEAN_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000800 }
801
Ben Murdochb8e0da22011-05-16 14:20:40 +0100802 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
803 CONSTANT_FUNCTION,
804 extra_ic_state,
805 cache_holder,
806 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()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000810 // If the function hasn't been compiled yet, we cannot do it now
811 // because it may cause GC. To avoid this issue, we return an
812 // internal error which will make sure we do not update any
813 // caches.
814 if (!function->is_compiled()) return Failure::InternalError();
815 // Compile the stub - only create stubs for fully compiled functions.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100816 CallStubCompiler compiler(
817 argc, in_loop, kind, extra_ic_state, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700818 { MaybeObject* maybe_code =
819 compiler.CompileCallConstant(object, holder, function, name, check);
820 if (!maybe_code->ToObject(&code)) return maybe_code;
821 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100822 Code::cast(code)->set_check_type(check);
Steve Blocka7e24c12009-10-30 11:49:00 +0000823 ASSERT_EQ(flags, Code::cast(code)->flags());
Steve Block44f0eee2011-05-26 01:26:41 +0100824 PROFILE(isolate_,
825 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100826 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100827 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700828 Object* result;
829 { MaybeObject* maybe_result =
830 map_holder->UpdateMapCodeCache(name, Code::cast(code));
831 if (!maybe_result->ToObject(&result)) return maybe_result;
832 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000833 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100834 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000835}
836
837
John Reck59135872010-11-02 12:39:01 -0700838MaybeObject* StubCache::ComputeCallField(int argc,
839 InLoopFlag in_loop,
840 Code::Kind kind,
841 String* name,
842 Object* object,
843 JSObject* holder,
844 int index) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000845 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100846 InlineCacheHolderFlag cache_holder =
847 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100848 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000849
850 // TODO(1233596): We cannot do receiver map check for non-JS objects
851 // because they may be represented as immediates without a
852 // map. Instead, we check against the map in the holder.
853 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
854 object = holder;
855 }
856
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100857 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000858 FIELD,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100859 Code::kNoExtraICState,
Steve Block8defd9f2010-07-08 12:39:36 +0100860 cache_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000861 in_loop,
862 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100863 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000864 if (code->IsUndefined()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100865 CallStubCompiler compiler(
866 argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700867 { MaybeObject* maybe_code =
868 compiler.CompileCallField(JSObject::cast(object),
869 holder,
870 index,
871 name);
872 if (!maybe_code->ToObject(&code)) return maybe_code;
873 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000874 ASSERT_EQ(flags, Code::cast(code)->flags());
Steve Block44f0eee2011-05-26 01:26:41 +0100875 PROFILE(isolate_,
876 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100877 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100878 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700879 Object* result;
880 { MaybeObject* maybe_result =
881 map_holder->UpdateMapCodeCache(name, Code::cast(code));
882 if (!maybe_result->ToObject(&result)) return maybe_result;
883 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000884 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100885 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000886}
887
888
John Reck59135872010-11-02 12:39:01 -0700889MaybeObject* StubCache::ComputeCallInterceptor(int argc,
890 Code::Kind kind,
891 String* name,
892 Object* object,
893 JSObject* holder) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000894 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100895 InlineCacheHolderFlag cache_holder =
896 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100897 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000898
899 // TODO(1233596): We cannot do receiver map check for non-JS objects
900 // because they may be represented as immediates without a
901 // map. Instead, we check against the map in the holder.
902 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
903 object = holder;
904 }
905
Ben Murdochb8e0da22011-05-16 14:20:40 +0100906 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
907 INTERCEPTOR,
908 Code::kNoExtraICState,
909 cache_holder,
910 NOT_IN_LOOP,
911 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100912 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000913 if (code->IsUndefined()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100914 CallStubCompiler compiler(
915 argc, NOT_IN_LOOP, kind, Code::kNoExtraICState, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700916 { MaybeObject* maybe_code =
917 compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
918 if (!maybe_code->ToObject(&code)) return maybe_code;
919 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000920 ASSERT_EQ(flags, Code::cast(code)->flags());
Steve Block44f0eee2011-05-26 01:26:41 +0100921 PROFILE(isolate(),
922 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100923 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
John Reck59135872010-11-02 12:39:01 -0700935MaybeObject* StubCache::ComputeCallNormal(int argc,
936 InLoopFlag in_loop,
937 Code::Kind kind,
938 String* name,
939 JSObject* receiver) {
940 Object* code;
941 { MaybeObject* maybe_code = ComputeCallNormal(argc, in_loop, kind);
942 if (!maybe_code->ToObject(&code)) return maybe_code;
943 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100944 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000945}
946
947
John Reck59135872010-11-02 12:39:01 -0700948MaybeObject* StubCache::ComputeCallGlobal(int argc,
949 InLoopFlag in_loop,
950 Code::Kind kind,
951 String* name,
952 JSObject* receiver,
953 GlobalObject* holder,
954 JSGlobalPropertyCell* cell,
955 JSFunction* function) {
Steve Block8defd9f2010-07-08 12:39:36 +0100956 InlineCacheHolderFlag cache_holder =
957 IC::GetCodeCacheForObject(receiver, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100958 JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100959 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
960 NORMAL,
961 Code::kNoExtraICState,
962 cache_holder,
963 in_loop,
964 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100965 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000966 if (code->IsUndefined()) {
967 // If the function hasn't been compiled yet, we cannot do it now
968 // because it may cause GC. To avoid this issue, we return an
969 // internal error which will make sure we do not update any
970 // caches.
971 if (!function->is_compiled()) return Failure::InternalError();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100972 CallStubCompiler compiler(
973 argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700974 { MaybeObject* maybe_code =
975 compiler.CompileCallGlobal(receiver, holder, cell, function, name);
976 if (!maybe_code->ToObject(&code)) return maybe_code;
977 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000978 ASSERT_EQ(flags, Code::cast(code)->flags());
Steve Block44f0eee2011-05-26 01:26:41 +0100979 PROFILE(isolate(),
980 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100981 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100982 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700983 Object* result;
984 { MaybeObject* maybe_result =
985 map_holder->UpdateMapCodeCache(name, Code::cast(code));
986 if (!maybe_result->ToObject(&result)) return maybe_result;
987 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000988 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100989 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000990}
991
992
Steve Block44f0eee2011-05-26 01:26:41 +0100993static Object* GetProbeValue(Isolate* isolate, Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000994 // Use raw_unchecked... so we don't get assert failures during GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100995 NumberDictionary* dictionary =
996 isolate->heap()->raw_unchecked_non_monomorphic_cache();
997 int entry = dictionary->FindEntry(isolate, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000998 if (entry != -1) return dictionary->ValueAt(entry);
Steve Block44f0eee2011-05-26 01:26:41 +0100999 return isolate->heap()->raw_unchecked_undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001000}
1001
1002
Steve Block44f0eee2011-05-26 01:26:41 +01001003MUST_USE_RESULT static MaybeObject* ProbeCache(Isolate* isolate,
1004 Code::Flags flags) {
1005 Heap* heap = isolate->heap();
1006 Object* probe = GetProbeValue(isolate, flags);
1007 if (probe != heap->undefined_value()) return probe;
Steve Blocka7e24c12009-10-30 11:49:00 +00001008 // Seed the cache with an undefined value to make sure that any
1009 // generated code object can always be inserted into the cache
1010 // without causing allocation failures.
John Reck59135872010-11-02 12:39:01 -07001011 Object* result;
1012 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01001013 heap->non_monomorphic_cache()->AtNumberPut(flags,
1014 heap->undefined_value());
John Reck59135872010-11-02 12:39:01 -07001015 if (!maybe_result->ToObject(&result)) return maybe_result;
1016 }
Steve Block44f0eee2011-05-26 01:26:41 +01001017 heap->public_set_non_monomorphic_cache(NumberDictionary::cast(result));
Steve Blocka7e24c12009-10-30 11:49:00 +00001018 return probe;
1019}
1020
1021
Steve Block44f0eee2011-05-26 01:26:41 +01001022static MaybeObject* FillCache(Isolate* isolate, MaybeObject* maybe_code) {
John Reck59135872010-11-02 12:39:01 -07001023 Object* code;
1024 if (maybe_code->ToObject(&code)) {
1025 if (code->IsCode()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001026 Heap* heap = isolate->heap();
1027 int entry = heap->non_monomorphic_cache()->FindEntry(
1028 Code::cast(code)->flags());
John Reck59135872010-11-02 12:39:01 -07001029 // The entry must be present see comment in ProbeCache.
1030 ASSERT(entry != -1);
Steve Block44f0eee2011-05-26 01:26:41 +01001031 ASSERT(heap->non_monomorphic_cache()->ValueAt(entry) ==
1032 heap->undefined_value());
1033 heap->non_monomorphic_cache()->ValueAtPut(entry, code);
1034 CHECK(GetProbeValue(isolate, Code::cast(code)->flags()) == code);
John Reck59135872010-11-02 12:39:01 -07001035 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001036 }
John Reck59135872010-11-02 12:39:01 -07001037 return maybe_code;
Steve Blocka7e24c12009-10-30 11:49:00 +00001038}
1039
1040
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001041Code* StubCache::FindCallInitialize(int argc,
1042 InLoopFlag in_loop,
1043 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001044 Code::Flags flags = Code::ComputeFlags(kind,
1045 in_loop,
1046 UNINITIALIZED,
1047 Code::kNoExtraICState,
1048 NORMAL,
1049 argc);
Steve Block44f0eee2011-05-26 01:26:41 +01001050 Object* result = ProbeCache(isolate(), flags)->ToObjectUnchecked();
1051 ASSERT(result != heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001052 // This might be called during the marking phase of the collector
1053 // hence the unchecked cast.
1054 return reinterpret_cast<Code*>(result);
1055}
1056
1057
John Reck59135872010-11-02 12:39:01 -07001058MaybeObject* StubCache::ComputeCallInitialize(int argc,
1059 InLoopFlag in_loop,
1060 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001061 Code::Flags flags = Code::ComputeFlags(kind,
1062 in_loop,
1063 UNINITIALIZED,
1064 Code::kNoExtraICState,
1065 NORMAL,
1066 argc);
John Reck59135872010-11-02 12:39:01 -07001067 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +01001068 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -07001069 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1070 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001071 if (!probe->IsUndefined()) return probe;
1072 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +01001073 return FillCache(isolate_, compiler.CompileCallInitialize(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001074}
1075
1076
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001077Handle<Code> StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop) {
1078 if (in_loop == IN_LOOP) {
1079 // Force the creation of the corresponding stub outside loops,
1080 // because it may be used when clearing the ICs later - it is
1081 // possible for a series of IC transitions to lose the in-loop
1082 // information, and the IC clearing code can't generate a stub
1083 // that it needs so we need to ensure it is generated already.
1084 ComputeCallInitialize(argc, NOT_IN_LOOP);
1085 }
Steve Block44f0eee2011-05-26 01:26:41 +01001086 CALL_HEAP_FUNCTION(isolate_,
1087 ComputeCallInitialize(argc, in_loop, Code::CALL_IC), Code);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001088}
1089
1090
1091Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
1092 InLoopFlag in_loop) {
1093 if (in_loop == IN_LOOP) {
1094 // Force the creation of the corresponding stub outside loops,
1095 // because it may be used when clearing the ICs later - it is
1096 // possible for a series of IC transitions to lose the in-loop
1097 // information, and the IC clearing code can't generate a stub
1098 // that it needs so we need to ensure it is generated already.
1099 ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
1100 }
1101 CALL_HEAP_FUNCTION(
Steve Block44f0eee2011-05-26 01:26:41 +01001102 isolate_,
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001103 ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC), Code);
1104}
1105
1106
John Reck59135872010-11-02 12:39:01 -07001107MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc,
1108 InLoopFlag in_loop,
1109 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001110 Code::Flags flags = Code::ComputeFlags(kind,
1111 in_loop,
1112 PREMONOMORPHIC,
1113 Code::kNoExtraICState,
1114 NORMAL,
1115 argc);
John Reck59135872010-11-02 12:39:01 -07001116 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +01001117 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -07001118 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1119 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001120 if (!probe->IsUndefined()) return probe;
1121 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +01001122 return FillCache(isolate_, compiler.CompileCallPreMonomorphic(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001123}
1124
1125
John Reck59135872010-11-02 12:39:01 -07001126MaybeObject* StubCache::ComputeCallNormal(int argc,
1127 InLoopFlag in_loop,
1128 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001129 Code::Flags flags = Code::ComputeFlags(kind,
1130 in_loop,
1131 MONOMORPHIC,
1132 Code::kNoExtraICState,
1133 NORMAL,
1134 argc);
John Reck59135872010-11-02 12:39:01 -07001135 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +01001136 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -07001137 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1138 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001139 if (!probe->IsUndefined()) return probe;
1140 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +01001141 return FillCache(isolate_, compiler.CompileCallNormal(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001142}
1143
1144
John Reck59135872010-11-02 12:39:01 -07001145MaybeObject* StubCache::ComputeCallMegamorphic(int argc,
1146 InLoopFlag in_loop,
1147 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001148 Code::Flags flags = Code::ComputeFlags(kind,
1149 in_loop,
1150 MEGAMORPHIC,
1151 Code::kNoExtraICState,
1152 NORMAL,
1153 argc);
John Reck59135872010-11-02 12:39:01 -07001154 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +01001155 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -07001156 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1157 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001158 if (!probe->IsUndefined()) return probe;
1159 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +01001160 return FillCache(isolate_, compiler.CompileCallMegamorphic(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001161}
1162
1163
John Reck59135872010-11-02 12:39:01 -07001164MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001165 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
1166 // and monomorphic stubs are not mixed up together in the stub cache.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001167 Code::Flags flags = Code::ComputeFlags(kind,
1168 NOT_IN_LOOP,
1169 MONOMORPHIC_PROTOTYPE_FAILURE,
1170 Code::kNoExtraICState,
1171 NORMAL,
1172 argc,
1173 OWN_MAP);
John Reck59135872010-11-02 12:39:01 -07001174 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +01001175 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -07001176 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1177 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001178 if (!probe->IsUndefined()) return probe;
1179 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +01001180 return FillCache(isolate_, compiler.CompileCallMiss(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001181}
1182
1183
1184#ifdef ENABLE_DEBUGGER_SUPPORT
John Reck59135872010-11-02 12:39:01 -07001185MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001186 Code::Flags flags = Code::ComputeFlags(kind,
1187 NOT_IN_LOOP,
1188 DEBUG_BREAK,
1189 Code::kNoExtraICState,
1190 NORMAL,
1191 argc);
John Reck59135872010-11-02 12:39:01 -07001192 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +01001193 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -07001194 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1195 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001196 if (!probe->IsUndefined()) return probe;
1197 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +01001198 return FillCache(isolate_, compiler.CompileCallDebugBreak(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001199}
1200
1201
John Reck59135872010-11-02 12:39:01 -07001202MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(int argc,
1203 Code::Kind kind) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001204 Code::Flags flags = Code::ComputeFlags(kind,
1205 NOT_IN_LOOP,
1206 DEBUG_PREPARE_STEP_IN,
1207 Code::kNoExtraICState,
1208 NORMAL,
1209 argc);
John Reck59135872010-11-02 12:39:01 -07001210 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +01001211 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -07001212 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1213 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001214 if (!probe->IsUndefined()) return probe;
1215 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +01001216 return FillCache(isolate_, compiler.CompileCallDebugPrepareStepIn(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001217}
1218#endif
1219
1220
Steve Blocka7e24c12009-10-30 11:49:00 +00001221void StubCache::Clear() {
1222 for (int i = 0; i < kPrimaryTableSize; i++) {
Steve Block44f0eee2011-05-26 01:26:41 +01001223 primary_[i].key = heap()->empty_string();
1224 primary_[i].value = isolate_->builtins()->builtin(
1225 Builtins::kIllegal);
Steve Blocka7e24c12009-10-30 11:49:00 +00001226 }
1227 for (int j = 0; j < kSecondaryTableSize; j++) {
Steve Block44f0eee2011-05-26 01:26:41 +01001228 secondary_[j].key = heap()->empty_string();
1229 secondary_[j].value = isolate_->builtins()->builtin(
1230 Builtins::kIllegal);
Steve Blocka7e24c12009-10-30 11:49:00 +00001231 }
1232}
1233
1234
Ben Murdochb0fe1622011-05-05 13:52:32 +01001235void StubCache::CollectMatchingMaps(ZoneMapList* types,
1236 String* name,
1237 Code::Flags flags) {
1238 for (int i = 0; i < kPrimaryTableSize; i++) {
1239 if (primary_[i].key == name) {
1240 Map* map = primary_[i].value->FindFirstMap();
1241 // Map can be NULL, if the stub is constant function call
1242 // with a primitive receiver.
1243 if (map == NULL) continue;
1244
1245 int offset = PrimaryOffset(name, flags, map);
1246 if (entry(primary_, offset) == &primary_[i]) {
1247 types->Add(Handle<Map>(map));
1248 }
1249 }
1250 }
1251
1252 for (int i = 0; i < kSecondaryTableSize; i++) {
1253 if (secondary_[i].key == name) {
1254 Map* map = secondary_[i].value->FindFirstMap();
1255 // Map can be NULL, if the stub is constant function call
1256 // with a primitive receiver.
1257 if (map == NULL) continue;
1258
1259 // Lookup in primary table and skip duplicates.
1260 int primary_offset = PrimaryOffset(name, flags, map);
1261 Entry* primary_entry = entry(primary_, primary_offset);
1262 if (primary_entry->key == name) {
1263 Map* primary_map = primary_entry->value->FindFirstMap();
1264 if (map == primary_map) continue;
1265 }
1266
1267 // Lookup in secondary table and add matches.
1268 int offset = SecondaryOffset(name, flags, primary_offset);
1269 if (entry(secondary_, offset) == &secondary_[i]) {
1270 types->Add(Handle<Map>(map));
1271 }
1272 }
1273 }
1274}
1275
1276
Steve Blocka7e24c12009-10-30 11:49:00 +00001277// ------------------------------------------------------------------------
1278// StubCompiler implementation.
1279
1280
Ben Murdoch8b112d22011-06-08 16:22:53 +01001281RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) {
Steve Blockd0582a62009-12-15 09:54:21 +00001282 ASSERT(args[0]->IsJSObject());
1283 ASSERT(args[1]->IsJSObject());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001284 AccessorInfo* callback = AccessorInfo::cast(args[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001285 Address getter_address = v8::ToCData<Address>(callback->getter());
1286 v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
1287 ASSERT(fun != NULL);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001288 v8::AccessorInfo info(&args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01001289 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001290 v8::Handle<v8::Value> result;
1291 {
1292 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001293 VMState state(isolate, EXTERNAL);
1294 ExternalCallbackScope call_scope(isolate, getter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001295 result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
1296 }
Steve Block44f0eee2011-05-26 01:26:41 +01001297 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1298 if (result.IsEmpty()) return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001299 return *v8::Utils::OpenHandle(*result);
1300}
1301
1302
Ben Murdoch8b112d22011-06-08 16:22:53 +01001303RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001304 JSObject* recv = JSObject::cast(args[0]);
1305 AccessorInfo* callback = AccessorInfo::cast(args[1]);
1306 Address setter_address = v8::ToCData<Address>(callback->setter());
1307 v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
1308 ASSERT(fun != NULL);
1309 Handle<String> name = args.at<String>(2);
1310 Handle<Object> value = args.at<Object>(3);
Steve Block44f0eee2011-05-26 01:26:41 +01001311 HandleScope scope(isolate);
1312 LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
1313 CustomArguments custom_args(isolate, callback->data(), recv, recv);
Steve Blocka7e24c12009-10-30 11:49:00 +00001314 v8::AccessorInfo info(custom_args.end());
1315 {
1316 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001317 VMState state(isolate, EXTERNAL);
1318 ExternalCallbackScope call_scope(isolate, setter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001319 fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
1320 }
Steve Block44f0eee2011-05-26 01:26:41 +01001321 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001322 return *value;
1323}
1324
Steve Block6ded16b2010-05-10 14:33:55 +01001325
1326static const int kAccessorInfoOffsetInInterceptorArgs = 2;
1327
1328
Steve Blocka7e24c12009-10-30 11:49:00 +00001329/**
1330 * Attempts to load a property with an interceptor (which must be present),
1331 * but doesn't search the prototype chain.
1332 *
1333 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
1334 * provide any value for the given name.
1335 */
Ben Murdoch8b112d22011-06-08 16:22:53 +01001336RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
Steve Block6ded16b2010-05-10 14:33:55 +01001337 Handle<String> name_handle = args.at<String>(0);
1338 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
1339 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1340 ASSERT(args[2]->IsJSObject()); // Receiver.
1341 ASSERT(args[3]->IsJSObject()); // Holder.
1342 ASSERT(args.length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001343
1344 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1345 v8::NamedPropertyGetter getter =
1346 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1347 ASSERT(getter != NULL);
1348
1349 {
1350 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001351 v8::AccessorInfo info(args.arguments() -
1352 kAccessorInfoOffsetInInterceptorArgs);
Steve Block44f0eee2011-05-26 01:26:41 +01001353 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001354 v8::Handle<v8::Value> r;
1355 {
1356 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001357 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001358 r = getter(v8::Utils::ToLocal(name_handle), info);
1359 }
Steve Block44f0eee2011-05-26 01:26:41 +01001360 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001361 if (!r.IsEmpty()) {
1362 return *v8::Utils::OpenHandle(*r);
1363 }
1364 }
1365
Steve Block44f0eee2011-05-26 01:26:41 +01001366 return isolate->heap()->no_interceptor_result_sentinel();
Steve Blocka7e24c12009-10-30 11:49:00 +00001367}
1368
1369
John Reck59135872010-11-02 12:39:01 -07001370static MaybeObject* ThrowReferenceError(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001371 // If the load is non-contextual, just return the undefined result.
1372 // Note that both keyed and non-keyed loads may end up here, so we
1373 // can't use either LoadIC or KeyedLoadIC constructors.
Steve Block44f0eee2011-05-26 01:26:41 +01001374 IC ic(IC::NO_EXTRA_FRAME, Isolate::Current());
Steve Blocka7e24c12009-10-30 11:49:00 +00001375 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01001376 if (!ic.SlowIsContextual()) return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001377
1378 // Throw a reference error.
1379 HandleScope scope;
1380 Handle<String> name_handle(name);
1381 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01001382 FACTORY->NewReferenceError("not_defined",
Steve Blocka7e24c12009-10-30 11:49:00 +00001383 HandleVector(&name_handle, 1));
Steve Block44f0eee2011-05-26 01:26:41 +01001384 return Isolate::Current()->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00001385}
1386
1387
John Reck59135872010-11-02 12:39:01 -07001388static MaybeObject* LoadWithInterceptor(Arguments* args,
1389 PropertyAttributes* attrs) {
Steve Block6ded16b2010-05-10 14:33:55 +01001390 Handle<String> name_handle = args->at<String>(0);
1391 Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
1392 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1393 Handle<JSObject> receiver_handle = args->at<JSObject>(2);
1394 Handle<JSObject> holder_handle = args->at<JSObject>(3);
1395 ASSERT(args->length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001396
Steve Block44f0eee2011-05-26 01:26:41 +01001397 Isolate* isolate = receiver_handle->GetIsolate();
1398
Steve Blocka7e24c12009-10-30 11:49:00 +00001399 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1400 v8::NamedPropertyGetter getter =
1401 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1402 ASSERT(getter != NULL);
1403
1404 {
1405 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001406 v8::AccessorInfo info(args->arguments() -
1407 kAccessorInfoOffsetInInterceptorArgs);
Steve Block44f0eee2011-05-26 01:26:41 +01001408 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001409 v8::Handle<v8::Value> r;
1410 {
1411 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001412 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001413 r = getter(v8::Utils::ToLocal(name_handle), info);
1414 }
Steve Block44f0eee2011-05-26 01:26:41 +01001415 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001416 if (!r.IsEmpty()) {
1417 *attrs = NONE;
1418 return *v8::Utils::OpenHandle(*r);
1419 }
1420 }
1421
John Reck59135872010-11-02 12:39:01 -07001422 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00001423 *receiver_handle,
1424 *name_handle,
1425 attrs);
Steve Block44f0eee2011-05-26 01:26:41 +01001426 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001427 return result;
1428}
1429
1430
1431/**
1432 * Loads a property with an interceptor performing post interceptor
1433 * lookup if interceptor failed.
1434 */
Ben Murdoch8b112d22011-06-08 16:22:53 +01001435RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001436 PropertyAttributes attr = NONE;
John Reck59135872010-11-02 12:39:01 -07001437 Object* result;
1438 { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
1439 if (!maybe_result->ToObject(&result)) return maybe_result;
1440 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001441
1442 // If the property is present, return it.
1443 if (attr != ABSENT) return result;
Steve Block6ded16b2010-05-10 14:33:55 +01001444 return ThrowReferenceError(String::cast(args[0]));
Steve Blocka7e24c12009-10-30 11:49:00 +00001445}
1446
1447
Ben Murdoch8b112d22011-06-08 16:22:53 +01001448RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001449 PropertyAttributes attr;
John Reck59135872010-11-02 12:39:01 -07001450 MaybeObject* result = LoadWithInterceptor(&args, &attr);
Steve Block44f0eee2011-05-26 01:26:41 +01001451 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001452 // This is call IC. In this case, we simply return the undefined result which
1453 // will lead to an exception when trying to invoke the result as a
1454 // function.
1455 return result;
1456}
1457
1458
Ben Murdoch8b112d22011-06-08 16:22:53 +01001459RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001460 ASSERT(args.length() == 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001461 JSObject* recv = JSObject::cast(args[0]);
1462 String* name = String::cast(args[1]);
1463 Object* value = args[2];
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001464 StrictModeFlag strict_mode =
1465 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1466 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001467 ASSERT(recv->HasNamedInterceptor());
1468 PropertyAttributes attr = NONE;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001469 MaybeObject* result = recv->SetPropertyWithInterceptor(
1470 name, value, attr, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001471 return result;
1472}
1473
1474
Ben Murdoch8b112d22011-06-08 16:22:53 +01001475RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001476 JSObject* receiver = JSObject::cast(args[0]);
Ben Murdochf87a2032010-10-22 12:50:53 +01001477 ASSERT(Smi::cast(args[1])->value() >= 0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001478 uint32_t index = Smi::cast(args[1])->value();
1479 return receiver->GetElementWithInterceptor(receiver, index);
1480}
1481
1482
John Reck59135872010-11-02 12:39:01 -07001483MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001484 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001485 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001486 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1487 if (kind == Code::CALL_IC) {
1488 CallIC::GenerateInitialize(masm(), argc);
1489 } else {
1490 KeyedCallIC::GenerateInitialize(masm(), argc);
1491 }
John Reck59135872010-11-02 12:39:01 -07001492 Object* result;
1493 { MaybeObject* maybe_result =
1494 GetCodeWithFlags(flags, "CompileCallInitialize");
1495 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001496 }
Steve Block44f0eee2011-05-26 01:26:41 +01001497 isolate()->counters()->call_initialize_stubs()->Increment();
John Reck59135872010-11-02 12:39:01 -07001498 Code* code = Code::cast(result);
1499 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001500 PROFILE(isolate(),
1501 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
John Reck59135872010-11-02 12:39:01 -07001502 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001503 GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001504 return result;
1505}
1506
1507
John Reck59135872010-11-02 12:39:01 -07001508MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001509 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001510 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1511 // The code of the PreMonomorphic stub is the same as the code
1512 // of the Initialized stub. They just differ on the code object flags.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001513 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1514 if (kind == Code::CALL_IC) {
1515 CallIC::GenerateInitialize(masm(), argc);
1516 } else {
1517 KeyedCallIC::GenerateInitialize(masm(), argc);
1518 }
John Reck59135872010-11-02 12:39:01 -07001519 Object* result;
1520 { MaybeObject* maybe_result =
1521 GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1522 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001523 }
Steve Block44f0eee2011-05-26 01:26:41 +01001524 isolate()->counters()->call_premonomorphic_stubs()->Increment();
John Reck59135872010-11-02 12:39:01 -07001525 Code* code = Code::cast(result);
1526 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001527 PROFILE(isolate(),
1528 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
John Reck59135872010-11-02 12:39:01 -07001529 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001530 GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001531 return result;
1532}
1533
1534
John Reck59135872010-11-02 12:39:01 -07001535MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001536 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001537 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001538 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1539 if (kind == Code::CALL_IC) {
1540 CallIC::GenerateNormal(masm(), argc);
1541 } else {
1542 KeyedCallIC::GenerateNormal(masm(), argc);
1543 }
John Reck59135872010-11-02 12:39:01 -07001544 Object* result;
1545 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallNormal");
1546 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001547 }
Steve Block44f0eee2011-05-26 01:26:41 +01001548 isolate()->counters()->call_normal_stubs()->Increment();
John Reck59135872010-11-02 12:39:01 -07001549 Code* code = Code::cast(result);
1550 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001551 PROFILE(isolate(),
1552 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
John Reck59135872010-11-02 12:39:01 -07001553 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001554 GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001555 return result;
1556}
1557
1558
John Reck59135872010-11-02 12:39:01 -07001559MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001560 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001561 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001562 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1563 if (kind == Code::CALL_IC) {
1564 CallIC::GenerateMegamorphic(masm(), argc);
1565 } else {
1566 KeyedCallIC::GenerateMegamorphic(masm(), argc);
1567 }
John Reck59135872010-11-02 12:39:01 -07001568 Object* result;
1569 { MaybeObject* maybe_result =
1570 GetCodeWithFlags(flags, "CompileCallMegamorphic");
1571 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001572 }
Steve Block44f0eee2011-05-26 01:26:41 +01001573 isolate()->counters()->call_megamorphic_stubs()->Increment();
John Reck59135872010-11-02 12:39:01 -07001574 Code* code = Code::cast(result);
1575 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001576 PROFILE(isolate(),
1577 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
John Reck59135872010-11-02 12:39:01 -07001578 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001579 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001580 return result;
1581}
1582
1583
John Reck59135872010-11-02 12:39:01 -07001584MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001585 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001586 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001587 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1588 if (kind == Code::CALL_IC) {
1589 CallIC::GenerateMiss(masm(), argc);
1590 } else {
1591 KeyedCallIC::GenerateMiss(masm(), argc);
1592 }
John Reck59135872010-11-02 12:39:01 -07001593 Object* result;
1594 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallMiss");
1595 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001596 }
Steve Block44f0eee2011-05-26 01:26:41 +01001597 isolate()->counters()->call_megamorphic_stubs()->Increment();
John Reck59135872010-11-02 12:39:01 -07001598 Code* code = Code::cast(result);
1599 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001600 PROFILE(isolate(),
1601 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
John Reck59135872010-11-02 12:39:01 -07001602 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001603 GDBJIT(AddCode(GDBJITInterface::CALL_MISS, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001604 return result;
1605}
1606
1607
1608#ifdef ENABLE_DEBUGGER_SUPPORT
John Reck59135872010-11-02 12:39:01 -07001609MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001610 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001611 Debug::GenerateCallICDebugBreak(masm());
John Reck59135872010-11-02 12:39:01 -07001612 Object* result;
1613 { MaybeObject* maybe_result =
1614 GetCodeWithFlags(flags, "CompileCallDebugBreak");
1615 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001616 }
John Reck59135872010-11-02 12:39:01 -07001617 Code* code = Code::cast(result);
1618 USE(code);
1619 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1620 USE(kind);
Steve Block44f0eee2011-05-26 01:26:41 +01001621 PROFILE(isolate(),
1622 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
John Reck59135872010-11-02 12:39:01 -07001623 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001624 return result;
1625}
1626
1627
John Reck59135872010-11-02 12:39:01 -07001628MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001629 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001630 // Use the same code for the the step in preparations as we do for
1631 // the miss case.
1632 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001633 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1634 if (kind == Code::CALL_IC) {
1635 CallIC::GenerateMiss(masm(), argc);
1636 } else {
1637 KeyedCallIC::GenerateMiss(masm(), argc);
1638 }
John Reck59135872010-11-02 12:39:01 -07001639 Object* result;
1640 { MaybeObject* maybe_result =
1641 GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1642 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001643 }
John Reck59135872010-11-02 12:39:01 -07001644 Code* code = Code::cast(result);
1645 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001646 PROFILE(isolate(),
1647 CodeCreateEvent(
1648 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1649 code,
1650 code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001651 return result;
1652}
1653#endif
1654
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001655#undef CALL_LOGGER_TAG
Steve Blocka7e24c12009-10-30 11:49:00 +00001656
John Reck59135872010-11-02 12:39:01 -07001657MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags,
1658 const char* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001659 // Check for allocation failures during stub compilation.
1660 if (failure_->IsFailure()) return failure_;
1661
1662 // Create code object in the heap.
1663 CodeDesc desc;
1664 masm_.GetCode(&desc);
Steve Block44f0eee2011-05-26 01:26:41 +01001665 MaybeObject* result = heap()->CreateCode(desc, flags, masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +00001666#ifdef ENABLE_DISASSEMBLER
1667 if (FLAG_print_code_stubs && !result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001668 Code::cast(result->ToObjectUnchecked())->Disassemble(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001669 }
1670#endif
1671 return result;
1672}
1673
1674
John Reck59135872010-11-02 12:39:01 -07001675MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001676 if (FLAG_print_code_stubs && (name != NULL)) {
1677 return GetCodeWithFlags(flags, *name->ToCString());
1678 }
1679 return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1680}
1681
Andrei Popescu402d9372010-02-26 13:31:12 +00001682
Leon Clarke4515c472010-02-03 11:58:03 +00001683void StubCompiler::LookupPostInterceptor(JSObject* holder,
1684 String* name,
1685 LookupResult* lookup) {
1686 holder->LocalLookupRealNamedProperty(name, lookup);
Andrei Popescu402d9372010-02-26 13:31:12 +00001687 if (!lookup->IsProperty()) {
1688 lookup->NotFound();
Leon Clarke4515c472010-02-03 11:58:03 +00001689 Object* proto = holder->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001690 if (!proto->IsNull()) {
Leon Clarke4515c472010-02-03 11:58:03 +00001691 proto->Lookup(name, lookup);
1692 }
1693 }
1694}
1695
1696
Steve Blocka7e24c12009-10-30 11:49:00 +00001697
John Reck59135872010-11-02 12:39:01 -07001698MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001699 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
John Reck59135872010-11-02 12:39:01 -07001700 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001701 if (!result->IsFailure()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001702 PROFILE(isolate(),
1703 CodeCreateEvent(Logger::LOAD_IC_TAG,
John Reck59135872010-11-02 12:39:01 -07001704 Code::cast(result->ToObjectUnchecked()),
1705 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001706 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1707 name,
1708 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001709 }
1710 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001711}
1712
1713
John Reck59135872010-11-02 12:39:01 -07001714MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001715 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
John Reck59135872010-11-02 12:39:01 -07001716 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001717 if (!result->IsFailure()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001718 PROFILE(isolate(),
1719 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
John Reck59135872010-11-02 12:39:01 -07001720 Code::cast(result->ToObjectUnchecked()),
1721 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001722 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1723 name,
1724 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001725 }
1726 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001727}
1728
1729
John Reck59135872010-11-02 12:39:01 -07001730MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001731 Code::Flags flags = Code::ComputeMonomorphicFlags(
1732 Code::STORE_IC, type, strict_mode_);
John Reck59135872010-11-02 12:39:01 -07001733 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001734 if (!result->IsFailure()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001735 PROFILE(isolate(),
1736 CodeCreateEvent(Logger::STORE_IC_TAG,
John Reck59135872010-11-02 12:39:01 -07001737 Code::cast(result->ToObjectUnchecked()),
1738 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001739 GDBJIT(AddCode(GDBJITInterface::STORE_IC,
1740 name,
1741 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001742 }
1743 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001744}
1745
1746
John Reck59135872010-11-02 12:39:01 -07001747MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001748 Code::Flags flags = Code::ComputeMonomorphicFlags(
1749 Code::KEYED_STORE_IC, type, strict_mode_);
John Reck59135872010-11-02 12:39:01 -07001750 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001751 if (!result->IsFailure()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001752 PROFILE(isolate(),
1753 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
John Reck59135872010-11-02 12:39:01 -07001754 Code::cast(result->ToObjectUnchecked()),
1755 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001756 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC,
1757 name,
1758 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001759 }
1760 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001761}
1762
1763
Steve Block8defd9f2010-07-08 12:39:36 +01001764CallStubCompiler::CallStubCompiler(int argc,
1765 InLoopFlag in_loop,
1766 Code::Kind kind,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001767 Code::ExtraICState extra_ic_state,
Steve Block8defd9f2010-07-08 12:39:36 +01001768 InlineCacheHolderFlag cache_holder)
Ben Murdochb8e0da22011-05-16 14:20:40 +01001769 : arguments_(argc),
1770 in_loop_(in_loop),
1771 kind_(kind),
1772 extra_ic_state_(extra_ic_state),
1773 cache_holder_(cache_holder) {
Steve Block8defd9f2010-07-08 12:39:36 +01001774}
1775
1776
Steve Block44f0eee2011-05-26 01:26:41 +01001777bool CallStubCompiler::HasCustomCallGenerator(JSFunction* function) {
1778 SharedFunctionInfo* info = function->shared();
1779 if (info->HasBuiltinFunctionId()) {
1780 BuiltinFunctionId id = info->builtin_function_id();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001781#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
Steve Block44f0eee2011-05-26 01:26:41 +01001782 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
Ben Murdochb0fe1622011-05-05 13:52:32 +01001783#undef CALL_GENERATOR_CASE
Steve Block44f0eee2011-05-26 01:26:41 +01001784 }
1785 CallOptimization optimization(function);
1786 if (optimization.is_simple_api_call()) {
1787 return true;
1788 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001789 return false;
1790}
1791
1792
Steve Block44f0eee2011-05-26 01:26:41 +01001793MaybeObject* CallStubCompiler::CompileCustomCall(Object* object,
John Reck59135872010-11-02 12:39:01 -07001794 JSObject* holder,
1795 JSGlobalPropertyCell* cell,
1796 JSFunction* function,
1797 String* fname) {
Steve Block44f0eee2011-05-26 01:26:41 +01001798 ASSERT(HasCustomCallGenerator(function));
1799
1800 SharedFunctionInfo* info = function->shared();
1801 if (info->HasBuiltinFunctionId()) {
1802 BuiltinFunctionId id = info->builtin_function_id();
1803#define CALL_GENERATOR_CASE(name) \
1804 if (id == k##name) { \
1805 return CallStubCompiler::Compile##name##Call(object, \
1806 holder, \
1807 cell, \
1808 function, \
1809 fname); \
1810 }
1811 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
Ben Murdochb0fe1622011-05-05 13:52:32 +01001812#undef CALL_GENERATOR_CASE
Steve Block44f0eee2011-05-26 01:26:41 +01001813 }
1814 CallOptimization optimization(function);
1815 ASSERT(optimization.is_simple_api_call());
1816 return CompileFastApiCall(optimization,
1817 object,
1818 holder,
1819 cell,
1820 function,
1821 fname);
Kristian Monsen25f61362010-05-21 11:50:48 +01001822}
1823
1824
John Reck59135872010-11-02 12:39:01 -07001825MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001826 int argc = arguments_.immediate();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001827 Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001828 type,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001829 extra_ic_state_,
Steve Block8defd9f2010-07-08 12:39:36 +01001830 cache_holder_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001831 in_loop_,
1832 argc);
1833 return GetCodeWithFlags(flags, name);
1834}
1835
1836
John Reck59135872010-11-02 12:39:01 -07001837MaybeObject* CallStubCompiler::GetCode(JSFunction* function) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001838 String* function_name = NULL;
1839 if (function->shared()->name()->IsString()) {
1840 function_name = String::cast(function->shared()->name());
1841 }
1842 return GetCode(CONSTANT_FUNCTION, function_name);
1843}
1844
1845
John Reck59135872010-11-02 12:39:01 -07001846MaybeObject* ConstructStubCompiler::GetCode() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001847 Code::Flags flags = Code::ComputeFlags(Code::STUB);
John Reck59135872010-11-02 12:39:01 -07001848 Object* result;
1849 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ConstructStub");
1850 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001851 }
John Reck59135872010-11-02 12:39:01 -07001852 Code* code = Code::cast(result);
1853 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001854 PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001855 GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001856 return result;
1857}
1858
1859
Steve Block6ded16b2010-05-10 14:33:55 +01001860CallOptimization::CallOptimization(LookupResult* lookup) {
1861 if (!lookup->IsProperty() || !lookup->IsCacheable() ||
1862 lookup->type() != CONSTANT_FUNCTION) {
1863 Initialize(NULL);
1864 } else {
1865 // We only optimize constant function calls.
1866 Initialize(lookup->GetConstantFunction());
1867 }
1868}
1869
1870CallOptimization::CallOptimization(JSFunction* function) {
1871 Initialize(function);
1872}
1873
1874
1875int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
1876 JSObject* holder) const {
1877 ASSERT(is_simple_api_call_);
1878 if (expected_receiver_type_ == NULL) return 0;
1879 int depth = 0;
1880 while (object != holder) {
1881 if (object->IsInstanceOf(expected_receiver_type_)) return depth;
1882 object = JSObject::cast(object->GetPrototype());
1883 ++depth;
1884 }
1885 if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
1886 return kInvalidProtoDepth;
1887}
1888
1889
1890void CallOptimization::Initialize(JSFunction* function) {
1891 constant_function_ = NULL;
1892 is_simple_api_call_ = false;
1893 expected_receiver_type_ = NULL;
1894 api_call_info_ = NULL;
1895
1896 if (function == NULL || !function->is_compiled()) return;
1897
1898 constant_function_ = function;
1899 AnalyzePossibleApiFunction(function);
1900}
1901
1902
1903void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
1904 SharedFunctionInfo* sfi = function->shared();
1905 if (!sfi->IsApiFunction()) return;
1906 FunctionTemplateInfo* info = sfi->get_api_func_data();
1907
1908 // Require a C++ callback.
1909 if (info->call_code()->IsUndefined()) return;
1910 api_call_info_ = CallHandlerInfo::cast(info->call_code());
1911
1912 // Accept signatures that either have no restrictions at all or
1913 // only have restrictions on the receiver.
1914 if (!info->signature()->IsUndefined()) {
1915 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1916 if (!signature->args()->IsUndefined()) return;
1917 if (!signature->receiver()->IsUndefined()) {
1918 expected_receiver_type_ =
1919 FunctionTemplateInfo::cast(signature->receiver());
1920 }
1921 }
1922
1923 is_simple_api_call_ = true;
1924}
1925
1926
Steve Block1e0659c2011-05-24 12:43:12 +01001927MaybeObject* ExternalArrayStubCompiler::GetCode(Code::Flags flags) {
1928 Object* result;
1929 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ExternalArrayStub");
1930 if (!maybe_result->ToObject(&result)) return maybe_result;
1931 }
1932 Code* code = Code::cast(result);
1933 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001934 PROFILE(isolate(),
1935 CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayStub"));
Steve Block1e0659c2011-05-24 12:43:12 +01001936 return result;
1937}
1938
1939
Steve Blocka7e24c12009-10-30 11:49:00 +00001940} } // namespace v8::internal