blob: 79cd7a0d22725d277d3ad93939bb136285dc21af [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// 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 Murdoch3fb3ca82011-12-02 17:19:32 +000032#include "code-stubs.h"
Ben Murdochb8e0da22011-05-16 14:20:40 +010033#include "gdb-jit.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034#include "ic-inl.h"
35#include "stub-cache.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010036#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000037
38namespace v8 {
39namespace internal {
40
41// -----------------------------------------------------------------------
42// StubCache implementation.
43
44
Steve Block44f0eee2011-05-26 01:26:41 +010045StubCache::StubCache(Isolate* isolate) : isolate_(isolate) {
46 ASSERT(isolate == Isolate::Current());
47 memset(primary_, 0, sizeof(primary_[0]) * StubCache::kPrimaryTableSize);
48 memset(secondary_, 0, sizeof(secondary_[0]) * StubCache::kSecondaryTableSize);
49}
50
Steve Blocka7e24c12009-10-30 11:49:00 +000051
52void StubCache::Initialize(bool create_heap_objects) {
53 ASSERT(IsPowerOf2(kPrimaryTableSize));
54 ASSERT(IsPowerOf2(kSecondaryTableSize));
55 if (create_heap_objects) {
56 HandleScope scope;
57 Clear();
58 }
59}
60
61
62Code* StubCache::Set(String* name, Map* map, Code* code) {
63 // Get the flags from the code.
64 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
65
66 // Validate that the name does not move on scavenge, and that we
67 // can use identity checks instead of string equality checks.
Steve Block44f0eee2011-05-26 01:26:41 +010068 ASSERT(!heap()->InNewSpace(name));
Steve Blocka7e24c12009-10-30 11:49:00 +000069 ASSERT(name->IsSymbol());
70
71 // The state bits are not important to the hash function because
72 // the stub cache only contains monomorphic stubs. Make sure that
73 // the bits are the least significant so they will be the ones
74 // masked out.
75 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
76 ASSERT(Code::kFlagsICStateShift == 0);
77
78 // Make sure that the code type is not included in the hash.
79 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
80
81 // Compute the primary entry.
82 int primary_offset = PrimaryOffset(name, flags, map);
83 Entry* primary = entry(primary_, primary_offset);
84 Code* hit = primary->value;
85
86 // If the primary entry has useful data in it, we retire it to the
87 // secondary cache before overwriting it.
Steve Block44f0eee2011-05-26 01:26:41 +010088 if (hit != isolate_->builtins()->builtin(Builtins::kIllegal)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000089 Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
90 int secondary_offset =
91 SecondaryOffset(primary->key, primary_flags, primary_offset);
92 Entry* secondary = entry(secondary_, secondary_offset);
93 *secondary = *primary;
94 }
95
96 // Update primary cache.
97 primary->key = name;
98 primary->value = code;
99 return code;
100}
101
102
John Reck59135872010-11-02 12:39:01 -0700103MaybeObject* StubCache::ComputeLoadNonexistent(String* name,
104 JSObject* receiver) {
Steve Block8defd9f2010-07-08 12:39:36 +0100105 ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
Steve Block6ded16b2010-05-10 14:33:55 +0100106 // If no global objects are present in the prototype chain, the load
107 // nonexistent IC stub can be shared for all names for a given map
108 // and we use the empty string for the map cache in that case. If
109 // there are global objects involved, we need to check global
110 // property cells in the stub and therefore the stub will be
111 // specific to the name.
Steve Block44f0eee2011-05-26 01:26:41 +0100112 String* cache_name = heap()->empty_string();
Steve Block6ded16b2010-05-10 14:33:55 +0100113 if (receiver->IsGlobalObject()) cache_name = name;
114 JSObject* last = receiver;
Steve Block44f0eee2011-05-26 01:26:41 +0100115 while (last->GetPrototype() != heap()->null_value()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100116 last = JSObject::cast(last->GetPrototype());
117 if (last->IsGlobalObject()) cache_name = name;
118 }
119 // Compile the stub that is either shared for all names or
120 // name specific if there are global objects involved.
121 Code::Flags flags =
122 Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
123 Object* code = receiver->map()->FindInCodeCache(cache_name, flags);
124 if (code->IsUndefined()) {
125 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700126 { MaybeObject* maybe_code =
127 compiler.CompileLoadNonexistent(cache_name, receiver, last);
128 if (!maybe_code->ToObject(&code)) return maybe_code;
129 }
Steve Block44f0eee2011-05-26 01:26:41 +0100130 PROFILE(isolate_,
131 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100132 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, cache_name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700133 Object* result;
134 { MaybeObject* maybe_result =
135 receiver->UpdateMapCodeCache(cache_name, Code::cast(code));
136 if (!maybe_result->ToObject(&result)) return maybe_result;
137 }
Steve Block6ded16b2010-05-10 14:33:55 +0100138 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100139 return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100140}
141
142
John Reck59135872010-11-02 12:39:01 -0700143MaybeObject* StubCache::ComputeLoadField(String* name,
144 JSObject* receiver,
145 JSObject* holder,
146 int field_index) {
Steve Block8defd9f2010-07-08 12:39:36 +0100147 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000148 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100149 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000150 if (code->IsUndefined()) {
151 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700152 { MaybeObject* maybe_code =
153 compiler.CompileLoadField(receiver, holder, field_index, name);
154 if (!maybe_code->ToObject(&code)) return maybe_code;
155 }
Steve Block44f0eee2011-05-26 01:26:41 +0100156 PROFILE(isolate_,
157 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100158 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700159 Object* result;
160 { MaybeObject* maybe_result =
161 receiver->UpdateMapCodeCache(name, Code::cast(code));
162 if (!maybe_result->ToObject(&result)) return maybe_result;
163 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000164 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100165 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000166}
167
168
John Reck59135872010-11-02 12:39:01 -0700169MaybeObject* StubCache::ComputeLoadCallback(String* name,
170 JSObject* receiver,
171 JSObject* holder,
172 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000173 ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
Steve Block8defd9f2010-07-08 12:39:36 +0100174 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000175 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100176 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000177 if (code->IsUndefined()) {
178 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700179 { MaybeObject* maybe_code =
180 compiler.CompileLoadCallback(name, receiver, holder, callback);
181 if (!maybe_code->ToObject(&code)) return maybe_code;
182 }
Steve Block44f0eee2011-05-26 01:26:41 +0100183 PROFILE(isolate_,
184 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100185 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700186 Object* result;
187 { MaybeObject* maybe_result =
188 receiver->UpdateMapCodeCache(name, Code::cast(code));
189 if (!maybe_result->ToObject(&result)) return maybe_result;
190 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000191 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100192 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000193}
194
195
John Reck59135872010-11-02 12:39:01 -0700196MaybeObject* StubCache::ComputeLoadConstant(String* name,
197 JSObject* receiver,
198 JSObject* holder,
199 Object* value) {
Steve Block8defd9f2010-07-08 12:39:36 +0100200 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000201 Code::Flags flags =
202 Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100203 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000204 if (code->IsUndefined()) {
205 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700206 { MaybeObject* maybe_code =
207 compiler.CompileLoadConstant(receiver, holder, value, name);
208 if (!maybe_code->ToObject(&code)) return maybe_code;
209 }
Steve Block44f0eee2011-05-26 01:26:41 +0100210 PROFILE(isolate_,
211 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100212 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700213 Object* result;
214 { MaybeObject* maybe_result =
215 receiver->UpdateMapCodeCache(name, Code::cast(code));
216 if (!maybe_result->ToObject(&result)) return maybe_result;
217 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000218 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100219 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000220}
221
222
John Reck59135872010-11-02 12:39:01 -0700223MaybeObject* StubCache::ComputeLoadInterceptor(String* name,
224 JSObject* receiver,
225 JSObject* holder) {
Steve Block8defd9f2010-07-08 12:39:36 +0100226 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000227 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100228 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000229 if (code->IsUndefined()) {
230 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700231 { MaybeObject* maybe_code =
232 compiler.CompileLoadInterceptor(receiver, holder, name);
233 if (!maybe_code->ToObject(&code)) return maybe_code;
234 }
Steve Block44f0eee2011-05-26 01:26:41 +0100235 PROFILE(isolate_,
236 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100237 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700238 Object* result;
239 { MaybeObject* maybe_result =
240 receiver->UpdateMapCodeCache(name, Code::cast(code));
241 if (!maybe_result->ToObject(&result)) return maybe_result;
242 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000243 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100244 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000245}
246
247
John Reck59135872010-11-02 12:39:01 -0700248MaybeObject* StubCache::ComputeLoadNormal() {
Steve Block44f0eee2011-05-26 01:26:41 +0100249 return isolate_->builtins()->builtin(Builtins::kLoadIC_Normal);
Steve Blocka7e24c12009-10-30 11:49:00 +0000250}
251
252
John Reck59135872010-11-02 12:39:01 -0700253MaybeObject* StubCache::ComputeLoadGlobal(String* name,
254 JSObject* receiver,
255 GlobalObject* holder,
256 JSGlobalPropertyCell* cell,
257 bool is_dont_delete) {
Steve Block8defd9f2010-07-08 12:39:36 +0100258 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000259 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100260 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000261 if (code->IsUndefined()) {
262 LoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700263 { MaybeObject* maybe_code = compiler.CompileLoadGlobal(receiver,
264 holder,
265 cell,
266 name,
267 is_dont_delete);
268 if (!maybe_code->ToObject(&code)) return maybe_code;
269 }
Steve Block44f0eee2011-05-26 01:26:41 +0100270 PROFILE(isolate_,
271 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100272 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700273 Object* result;
274 { MaybeObject* maybe_result =
275 receiver->UpdateMapCodeCache(name, Code::cast(code));
276 if (!maybe_result->ToObject(&result)) return maybe_result;
277 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000278 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100279 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000280}
281
282
John Reck59135872010-11-02 12:39:01 -0700283MaybeObject* StubCache::ComputeKeyedLoadField(String* name,
284 JSObject* receiver,
285 JSObject* holder,
286 int field_index) {
Steve Block8defd9f2010-07-08 12:39:36 +0100287 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000288 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100289 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000290 if (code->IsUndefined()) {
291 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700292 { MaybeObject* maybe_code =
293 compiler.CompileLoadField(name, receiver, holder, field_index);
294 if (!maybe_code->ToObject(&code)) return maybe_code;
295 }
Steve Block44f0eee2011-05-26 01:26:41 +0100296 PROFILE(isolate_,
297 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100298 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700299 Object* result;
300 { MaybeObject* maybe_result =
301 receiver->UpdateMapCodeCache(name, Code::cast(code));
302 if (!maybe_result->ToObject(&result)) return maybe_result;
303 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000304 }
305 return code;
306}
307
308
John Reck59135872010-11-02 12:39:01 -0700309MaybeObject* StubCache::ComputeKeyedLoadConstant(String* name,
310 JSObject* receiver,
311 JSObject* holder,
312 Object* value) {
Steve Block8defd9f2010-07-08 12:39:36 +0100313 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000314 Code::Flags flags =
315 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100316 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000317 if (code->IsUndefined()) {
318 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700319 { MaybeObject* maybe_code =
320 compiler.CompileLoadConstant(name, receiver, holder, value);
321 if (!maybe_code->ToObject(&code)) return maybe_code;
322 }
Steve Block44f0eee2011-05-26 01:26:41 +0100323 PROFILE(isolate_,
324 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100325 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700326 Object* result;
327 { MaybeObject* maybe_result =
328 receiver->UpdateMapCodeCache(name, Code::cast(code));
329 if (!maybe_result->ToObject(&result)) return maybe_result;
330 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000331 }
332 return code;
333}
334
335
John Reck59135872010-11-02 12:39:01 -0700336MaybeObject* StubCache::ComputeKeyedLoadInterceptor(String* name,
337 JSObject* receiver,
338 JSObject* holder) {
Steve Block8defd9f2010-07-08 12:39:36 +0100339 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000340 Code::Flags flags =
341 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100342 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000343 if (code->IsUndefined()) {
344 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700345 { MaybeObject* maybe_code =
346 compiler.CompileLoadInterceptor(receiver, holder, name);
347 if (!maybe_code->ToObject(&code)) return maybe_code;
348 }
Steve Block44f0eee2011-05-26 01:26:41 +0100349 PROFILE(isolate_,
350 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100351 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700352 Object* result;
353 { MaybeObject* maybe_result =
354 receiver->UpdateMapCodeCache(name, Code::cast(code));
355 if (!maybe_result->ToObject(&result)) return maybe_result;
356 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000357 }
358 return code;
359}
360
361
John Reck59135872010-11-02 12:39:01 -0700362MaybeObject* StubCache::ComputeKeyedLoadCallback(String* name,
363 JSObject* receiver,
364 JSObject* holder,
365 AccessorInfo* callback) {
Steve Block8defd9f2010-07-08 12:39:36 +0100366 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000367 Code::Flags flags =
368 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100369 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000370 if (code->IsUndefined()) {
371 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700372 { MaybeObject* maybe_code =
373 compiler.CompileLoadCallback(name, receiver, holder, callback);
374 if (!maybe_code->ToObject(&code)) return maybe_code;
375 }
Steve Block44f0eee2011-05-26 01:26:41 +0100376 PROFILE(isolate_,
377 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100378 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700379 Object* result;
380 { MaybeObject* maybe_result =
381 receiver->UpdateMapCodeCache(name, Code::cast(code));
382 if (!maybe_result->ToObject(&result)) return maybe_result;
383 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000384 }
385 return code;
386}
387
388
389
John Reck59135872010-11-02 12:39:01 -0700390MaybeObject* StubCache::ComputeKeyedLoadArrayLength(String* name,
391 JSArray* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000392 Code::Flags flags =
393 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Steve Block8defd9f2010-07-08 12:39:36 +0100394 ASSERT(receiver->IsJSObject());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100395 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000396 if (code->IsUndefined()) {
397 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700398 { MaybeObject* maybe_code = compiler.CompileLoadArrayLength(name);
399 if (!maybe_code->ToObject(&code)) return maybe_code;
400 }
Steve Block44f0eee2011-05-26 01:26:41 +0100401 PROFILE(isolate_,
402 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100403 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700404 Object* result;
405 { MaybeObject* maybe_result =
406 receiver->UpdateMapCodeCache(name, Code::cast(code));
407 if (!maybe_result->ToObject(&result)) return maybe_result;
408 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000409 }
410 return code;
411}
412
413
John Reck59135872010-11-02 12:39:01 -0700414MaybeObject* StubCache::ComputeKeyedLoadStringLength(String* name,
415 String* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000416 Code::Flags flags =
417 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Steve Block8defd9f2010-07-08 12:39:36 +0100418 Map* map = receiver->map();
419 Object* code = map->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000420 if (code->IsUndefined()) {
421 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700422 { MaybeObject* maybe_code = compiler.CompileLoadStringLength(name);
423 if (!maybe_code->ToObject(&code)) return maybe_code;
424 }
Steve Block44f0eee2011-05-26 01:26:41 +0100425 PROFILE(isolate_,
426 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100427 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700428 Object* result;
429 { MaybeObject* maybe_result = map->UpdateCodeCache(name, Code::cast(code));
430 if (!maybe_result->ToObject(&result)) return maybe_result;
431 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000432 }
433 return code;
434}
435
436
John Reck59135872010-11-02 12:39:01 -0700437MaybeObject* StubCache::ComputeKeyedLoadFunctionPrototype(
438 String* name,
439 JSFunction* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000440 Code::Flags flags =
441 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100442 Object* code = receiver->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000443 if (code->IsUndefined()) {
444 KeyedLoadStubCompiler compiler;
John Reck59135872010-11-02 12:39:01 -0700445 { MaybeObject* maybe_code = compiler.CompileLoadFunctionPrototype(name);
446 if (!maybe_code->ToObject(&code)) return maybe_code;
447 }
Steve Block44f0eee2011-05-26 01:26:41 +0100448 PROFILE(isolate_,
449 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100450 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700451 Object* result;
452 { MaybeObject* maybe_result =
453 receiver->UpdateMapCodeCache(name, Code::cast(code));
454 if (!maybe_result->ToObject(&result)) return maybe_result;
455 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000456 }
457 return code;
458}
459
460
John Reck59135872010-11-02 12:39:01 -0700461MaybeObject* StubCache::ComputeStoreField(String* name,
462 JSObject* receiver,
463 int field_index,
Steve Block1e0659c2011-05-24 12:43:12 +0100464 Map* transition,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100465 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000466 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
Steve Block1e0659c2011-05-24 12:43:12 +0100467 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100468 Code::STORE_IC, type, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000469 Object* code = receiver->map()->FindInCodeCache(name, flags);
470 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100471 StoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700472 { MaybeObject* maybe_code =
473 compiler.CompileStoreField(receiver, field_index, transition, name);
474 if (!maybe_code->ToObject(&code)) return maybe_code;
475 }
Steve Block44f0eee2011-05-26 01:26:41 +0100476 PROFILE(isolate_,
477 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100478 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700479 Object* result;
480 { MaybeObject* maybe_result =
481 receiver->UpdateMapCodeCache(name, Code::cast(code));
482 if (!maybe_result->ToObject(&result)) return maybe_result;
483 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000484 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100485 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000486}
487
488
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000489MaybeObject* StubCache::ComputeKeyedLoadOrStoreElement(
Ben Murdoch257744e2011-11-30 15:57:28 +0000490 JSObject* receiver,
491 bool is_store,
492 StrictModeFlag strict_mode) {
493 Code::Flags flags =
494 Code::ComputeMonomorphicFlags(
495 is_store ? Code::KEYED_STORE_IC :
496 Code::KEYED_LOAD_IC,
497 NORMAL,
498 strict_mode);
499 String* name = is_store
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000500 ? isolate()->heap()->KeyedStoreElementMonomorphic_symbol()
501 : isolate()->heap()->KeyedLoadElementMonomorphic_symbol();
Ben Murdoch257744e2011-11-30 15:57:28 +0000502 Object* maybe_code = receiver->map()->FindInCodeCache(name, flags);
503 if (!maybe_code->IsUndefined()) return Code::cast(maybe_code);
504
505 MaybeObject* maybe_new_code = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000506 Map* receiver_map = receiver->map();
Ben Murdoch257744e2011-11-30 15:57:28 +0000507 if (is_store) {
508 KeyedStoreStubCompiler compiler(strict_mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000509 maybe_new_code = compiler.CompileStoreElement(receiver_map);
Ben Murdoch257744e2011-11-30 15:57:28 +0000510 } else {
511 KeyedLoadStubCompiler compiler;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000512 maybe_new_code = compiler.CompileLoadElement(receiver_map);
Ben Murdoch257744e2011-11-30 15:57:28 +0000513 }
514 Code* code;
515 if (!maybe_new_code->To(&code)) return maybe_new_code;
516 if (is_store) {
517 PROFILE(isolate_,
518 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
519 Code::cast(code), 0));
520 } else {
521 PROFILE(isolate_,
522 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
523 Code::cast(code), 0));
524 }
525 ASSERT(code->IsCode());
526 Object* result;
527 { MaybeObject* maybe_result =
528 receiver->UpdateMapCodeCache(name, Code::cast(code));
529 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Block1e0659c2011-05-24 12:43:12 +0100530 }
531 return code;
532}
533
534
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100535MaybeObject* StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +0100536 return isolate_->builtins()->builtin((strict_mode == kStrictMode)
537 ? Builtins::kStoreIC_Normal_Strict
538 : Builtins::kStoreIC_Normal);
Steve Block8defd9f2010-07-08 12:39:36 +0100539}
540
541
John Reck59135872010-11-02 12:39:01 -0700542MaybeObject* StubCache::ComputeStoreGlobal(String* name,
543 GlobalObject* receiver,
Steve Block1e0659c2011-05-24 12:43:12 +0100544 JSGlobalPropertyCell* cell,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100545 StrictModeFlag strict_mode) {
Steve Block1e0659c2011-05-24 12:43:12 +0100546 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100547 Code::STORE_IC, NORMAL, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000548 Object* code = receiver->map()->FindInCodeCache(name, flags);
549 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100550 StoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700551 { MaybeObject* maybe_code =
552 compiler.CompileStoreGlobal(receiver, cell, name);
553 if (!maybe_code->ToObject(&code)) return maybe_code;
554 }
Steve Block44f0eee2011-05-26 01:26:41 +0100555 PROFILE(isolate_,
556 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100557 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700558 Object* result;
559 { MaybeObject* maybe_result =
560 receiver->UpdateMapCodeCache(name, Code::cast(code));
561 if (!maybe_result->ToObject(&result)) return maybe_result;
562 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000563 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100564 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000565}
566
567
Steve Block1e0659c2011-05-24 12:43:12 +0100568MaybeObject* StubCache::ComputeStoreCallback(
569 String* name,
570 JSObject* receiver,
571 AccessorInfo* callback,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100572 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000573 ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
Steve Block1e0659c2011-05-24 12:43:12 +0100574 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100575 Code::STORE_IC, CALLBACKS, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000576 Object* code = receiver->map()->FindInCodeCache(name, flags);
577 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100578 StoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700579 { MaybeObject* maybe_code =
580 compiler.CompileStoreCallback(receiver, callback, name);
581 if (!maybe_code->ToObject(&code)) return maybe_code;
582 }
Steve Block44f0eee2011-05-26 01:26:41 +0100583 PROFILE(isolate_,
584 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100585 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700586 Object* result;
587 { MaybeObject* maybe_result =
588 receiver->UpdateMapCodeCache(name, Code::cast(code));
589 if (!maybe_result->ToObject(&result)) return maybe_result;
590 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000591 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100592 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000593}
594
595
Steve Block1e0659c2011-05-24 12:43:12 +0100596MaybeObject* StubCache::ComputeStoreInterceptor(
597 String* name,
598 JSObject* receiver,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100599 StrictModeFlag strict_mode) {
Steve Block1e0659c2011-05-24 12:43:12 +0100600 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100601 Code::STORE_IC, INTERCEPTOR, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000602 Object* code = receiver->map()->FindInCodeCache(name, flags);
603 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100604 StoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700605 { MaybeObject* maybe_code =
606 compiler.CompileStoreInterceptor(receiver, name);
607 if (!maybe_code->ToObject(&code)) return maybe_code;
608 }
Steve Block44f0eee2011-05-26 01:26:41 +0100609 PROFILE(isolate_,
610 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100611 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700612 Object* result;
613 { MaybeObject* maybe_result =
614 receiver->UpdateMapCodeCache(name, Code::cast(code));
615 if (!maybe_result->ToObject(&result)) return maybe_result;
616 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000617 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100618 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000619}
620
621
John Reck59135872010-11-02 12:39:01 -0700622MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
623 JSObject* receiver,
624 int field_index,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100625 Map* transition,
626 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000627 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100628 Code::Flags flags = Code::ComputeMonomorphicFlags(
629 Code::KEYED_STORE_IC, type, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000630 Object* code = receiver->map()->FindInCodeCache(name, flags);
631 if (code->IsUndefined()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100632 KeyedStoreStubCompiler compiler(strict_mode);
John Reck59135872010-11-02 12:39:01 -0700633 { MaybeObject* maybe_code =
634 compiler.CompileStoreField(receiver, field_index, transition, name);
635 if (!maybe_code->ToObject(&code)) return maybe_code;
636 }
Steve Block44f0eee2011-05-26 01:26:41 +0100637 PROFILE(isolate(),
638 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
639 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100640 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700641 Object* result;
642 { MaybeObject* maybe_result =
643 receiver->UpdateMapCodeCache(name, Code::cast(code));
644 if (!maybe_result->ToObject(&result)) return maybe_result;
645 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000646 }
647 return code;
648}
649
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100650#define CALL_LOGGER_TAG(kind, type) \
651 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
Steve Blocka7e24c12009-10-30 11:49:00 +0000652
John Reck59135872010-11-02 12:39:01 -0700653MaybeObject* StubCache::ComputeCallConstant(int argc,
654 InLoopFlag in_loop,
655 Code::Kind kind,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100656 Code::ExtraICState extra_ic_state,
John Reck59135872010-11-02 12:39:01 -0700657 String* name,
658 Object* object,
659 JSObject* holder,
660 JSFunction* function) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000661 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100662 InlineCacheHolderFlag cache_holder =
663 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100664 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000665
666 // Compute check type based on receiver/holder.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100667 CheckType check = RECEIVER_MAP_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000668 if (object->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100669 check = STRING_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000670 } else if (object->IsNumber()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100671 check = NUMBER_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000672 } else if (object->IsBoolean()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100673 check = BOOLEAN_CHECK;
Steve Blocka7e24c12009-10-30 11:49:00 +0000674 }
675
Ben Murdochb8e0da22011-05-16 14:20:40 +0100676 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
677 CONSTANT_FUNCTION,
678 extra_ic_state,
679 cache_holder,
680 in_loop,
681 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100682 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000683 if (code->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000684 // If the function hasn't been compiled yet, we cannot do it now
685 // because it may cause GC. To avoid this issue, we return an
686 // internal error which will make sure we do not update any
687 // caches.
688 if (!function->is_compiled()) return Failure::InternalError();
689 // Compile the stub - only create stubs for fully compiled functions.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100690 CallStubCompiler compiler(
691 argc, in_loop, kind, extra_ic_state, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700692 { MaybeObject* maybe_code =
693 compiler.CompileCallConstant(object, holder, function, name, check);
694 if (!maybe_code->ToObject(&code)) return maybe_code;
695 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100696 Code::cast(code)->set_check_type(check);
Steve Blocka7e24c12009-10-30 11:49:00 +0000697 ASSERT_EQ(flags, Code::cast(code)->flags());
Steve Block44f0eee2011-05-26 01:26:41 +0100698 PROFILE(isolate_,
699 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100700 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100701 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700702 Object* result;
703 { MaybeObject* maybe_result =
704 map_holder->UpdateMapCodeCache(name, Code::cast(code));
705 if (!maybe_result->ToObject(&result)) return maybe_result;
706 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000707 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100708 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000709}
710
711
John Reck59135872010-11-02 12:39:01 -0700712MaybeObject* StubCache::ComputeCallField(int argc,
713 InLoopFlag in_loop,
714 Code::Kind kind,
Ben Murdoch257744e2011-11-30 15:57:28 +0000715 Code::ExtraICState extra_ic_state,
John Reck59135872010-11-02 12:39:01 -0700716 String* name,
717 Object* object,
718 JSObject* holder,
719 int index) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000720 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100721 InlineCacheHolderFlag cache_holder =
722 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100723 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000724
725 // TODO(1233596): We cannot do receiver map check for non-JS objects
726 // because they may be represented as immediates without a
727 // map. Instead, we check against the map in the holder.
728 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
729 object = holder;
730 }
731
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100732 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
Steve Blocka7e24c12009-10-30 11:49:00 +0000733 FIELD,
Ben Murdoch257744e2011-11-30 15:57:28 +0000734 extra_ic_state,
Steve Block8defd9f2010-07-08 12:39:36 +0100735 cache_holder,
Steve Blocka7e24c12009-10-30 11:49:00 +0000736 in_loop,
737 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100738 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000739 if (code->IsUndefined()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100740 CallStubCompiler compiler(
Ben Murdoch257744e2011-11-30 15:57:28 +0000741 argc, in_loop, kind, extra_ic_state, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700742 { MaybeObject* maybe_code =
743 compiler.CompileCallField(JSObject::cast(object),
744 holder,
745 index,
746 name);
747 if (!maybe_code->ToObject(&code)) return maybe_code;
748 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000749 ASSERT_EQ(flags, Code::cast(code)->flags());
Steve Block44f0eee2011-05-26 01:26:41 +0100750 PROFILE(isolate_,
751 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100752 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100753 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700754 Object* result;
755 { MaybeObject* maybe_result =
756 map_holder->UpdateMapCodeCache(name, Code::cast(code));
757 if (!maybe_result->ToObject(&result)) return maybe_result;
758 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000759 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100760 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000761}
762
763
Ben Murdoch257744e2011-11-30 15:57:28 +0000764MaybeObject* StubCache::ComputeCallInterceptor(
765 int argc,
766 Code::Kind kind,
767 Code::ExtraICState extra_ic_state,
768 String* name,
769 Object* object,
770 JSObject* holder) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000771 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100772 InlineCacheHolderFlag cache_holder =
773 IC::GetCodeCacheForObject(object, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100774 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000775
776 // TODO(1233596): We cannot do receiver map check for non-JS objects
777 // because they may be represented as immediates without a
778 // map. Instead, we check against the map in the holder.
779 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
780 object = holder;
781 }
782
Ben Murdochb8e0da22011-05-16 14:20:40 +0100783 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
784 INTERCEPTOR,
Ben Murdoch257744e2011-11-30 15:57:28 +0000785 extra_ic_state,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100786 cache_holder,
787 NOT_IN_LOOP,
788 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100789 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000790 if (code->IsUndefined()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100791 CallStubCompiler compiler(
Ben Murdoch257744e2011-11-30 15:57:28 +0000792 argc, NOT_IN_LOOP, kind, extra_ic_state, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700793 { MaybeObject* maybe_code =
794 compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
795 if (!maybe_code->ToObject(&code)) return maybe_code;
796 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000797 ASSERT_EQ(flags, Code::cast(code)->flags());
Steve Block44f0eee2011-05-26 01:26:41 +0100798 PROFILE(isolate(),
799 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100800 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100801 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700802 Object* result;
803 { MaybeObject* maybe_result =
804 map_holder->UpdateMapCodeCache(name, Code::cast(code));
805 if (!maybe_result->ToObject(&result)) return maybe_result;
806 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000807 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100808 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000809}
810
811
John Reck59135872010-11-02 12:39:01 -0700812MaybeObject* StubCache::ComputeCallNormal(int argc,
813 InLoopFlag in_loop,
814 Code::Kind kind,
Ben Murdoch257744e2011-11-30 15:57:28 +0000815 Code::ExtraICState extra_ic_state,
John Reck59135872010-11-02 12:39:01 -0700816 String* name,
817 JSObject* receiver) {
818 Object* code;
Ben Murdoch257744e2011-11-30 15:57:28 +0000819 { MaybeObject* maybe_code =
820 ComputeCallNormal(argc, in_loop, kind, extra_ic_state);
John Reck59135872010-11-02 12:39:01 -0700821 if (!maybe_code->ToObject(&code)) return maybe_code;
822 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100823 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000824}
825
826
John Reck59135872010-11-02 12:39:01 -0700827MaybeObject* StubCache::ComputeCallGlobal(int argc,
828 InLoopFlag in_loop,
829 Code::Kind kind,
Ben Murdoch257744e2011-11-30 15:57:28 +0000830 Code::ExtraICState extra_ic_state,
John Reck59135872010-11-02 12:39:01 -0700831 String* name,
832 JSObject* receiver,
833 GlobalObject* holder,
834 JSGlobalPropertyCell* cell,
835 JSFunction* function) {
Steve Block8defd9f2010-07-08 12:39:36 +0100836 InlineCacheHolderFlag cache_holder =
837 IC::GetCodeCacheForObject(receiver, holder);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100838 JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100839 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
840 NORMAL,
Ben Murdoch257744e2011-11-30 15:57:28 +0000841 extra_ic_state,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100842 cache_holder,
843 in_loop,
844 argc);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100845 Object* code = map_holder->map()->FindInCodeCache(name, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000846 if (code->IsUndefined()) {
847 // If the function hasn't been compiled yet, we cannot do it now
848 // because it may cause GC. To avoid this issue, we return an
849 // internal error which will make sure we do not update any
850 // caches.
851 if (!function->is_compiled()) return Failure::InternalError();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100852 CallStubCompiler compiler(
Ben Murdoch257744e2011-11-30 15:57:28 +0000853 argc, in_loop, kind, extra_ic_state, cache_holder);
John Reck59135872010-11-02 12:39:01 -0700854 { MaybeObject* maybe_code =
855 compiler.CompileCallGlobal(receiver, holder, cell, function, name);
856 if (!maybe_code->ToObject(&code)) return maybe_code;
857 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000858 ASSERT_EQ(flags, Code::cast(code)->flags());
Steve Block44f0eee2011-05-26 01:26:41 +0100859 PROFILE(isolate(),
860 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100861 Code::cast(code), name));
Ben Murdochb8e0da22011-05-16 14:20:40 +0100862 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
John Reck59135872010-11-02 12:39:01 -0700863 Object* result;
864 { MaybeObject* maybe_result =
865 map_holder->UpdateMapCodeCache(name, Code::cast(code));
866 if (!maybe_result->ToObject(&result)) return maybe_result;
867 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000868 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100869 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000870}
871
872
Steve Block44f0eee2011-05-26 01:26:41 +0100873static Object* GetProbeValue(Isolate* isolate, Code::Flags flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000874 // Use raw_unchecked... so we don't get assert failures during GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100875 NumberDictionary* dictionary =
876 isolate->heap()->raw_unchecked_non_monomorphic_cache();
877 int entry = dictionary->FindEntry(isolate, flags);
Steve Blocka7e24c12009-10-30 11:49:00 +0000878 if (entry != -1) return dictionary->ValueAt(entry);
Steve Block44f0eee2011-05-26 01:26:41 +0100879 return isolate->heap()->raw_unchecked_undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000880}
881
882
Steve Block44f0eee2011-05-26 01:26:41 +0100883MUST_USE_RESULT static MaybeObject* ProbeCache(Isolate* isolate,
884 Code::Flags flags) {
885 Heap* heap = isolate->heap();
886 Object* probe = GetProbeValue(isolate, flags);
887 if (probe != heap->undefined_value()) return probe;
Steve Blocka7e24c12009-10-30 11:49:00 +0000888 // Seed the cache with an undefined value to make sure that any
889 // generated code object can always be inserted into the cache
890 // without causing allocation failures.
John Reck59135872010-11-02 12:39:01 -0700891 Object* result;
892 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +0100893 heap->non_monomorphic_cache()->AtNumberPut(flags,
894 heap->undefined_value());
John Reck59135872010-11-02 12:39:01 -0700895 if (!maybe_result->ToObject(&result)) return maybe_result;
896 }
Steve Block44f0eee2011-05-26 01:26:41 +0100897 heap->public_set_non_monomorphic_cache(NumberDictionary::cast(result));
Steve Blocka7e24c12009-10-30 11:49:00 +0000898 return probe;
899}
900
901
Steve Block44f0eee2011-05-26 01:26:41 +0100902static MaybeObject* FillCache(Isolate* isolate, MaybeObject* maybe_code) {
John Reck59135872010-11-02 12:39:01 -0700903 Object* code;
904 if (maybe_code->ToObject(&code)) {
905 if (code->IsCode()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100906 Heap* heap = isolate->heap();
907 int entry = heap->non_monomorphic_cache()->FindEntry(
908 Code::cast(code)->flags());
John Reck59135872010-11-02 12:39:01 -0700909 // The entry must be present see comment in ProbeCache.
910 ASSERT(entry != -1);
Steve Block44f0eee2011-05-26 01:26:41 +0100911 ASSERT(heap->non_monomorphic_cache()->ValueAt(entry) ==
912 heap->undefined_value());
913 heap->non_monomorphic_cache()->ValueAtPut(entry, code);
914 CHECK(GetProbeValue(isolate, Code::cast(code)->flags()) == code);
John Reck59135872010-11-02 12:39:01 -0700915 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000916 }
John Reck59135872010-11-02 12:39:01 -0700917 return maybe_code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000918}
919
920
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100921Code* StubCache::FindCallInitialize(int argc,
922 InLoopFlag in_loop,
Ben Murdoch257744e2011-11-30 15:57:28 +0000923 RelocInfo::Mode mode,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100924 Code::Kind kind) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000925 Code::ExtraICState extra_state =
926 CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
927 CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100928 Code::Flags flags = Code::ComputeFlags(kind,
929 in_loop,
930 UNINITIALIZED,
Ben Murdoch257744e2011-11-30 15:57:28 +0000931 extra_state,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100932 NORMAL,
933 argc);
Steve Block44f0eee2011-05-26 01:26:41 +0100934 Object* result = ProbeCache(isolate(), flags)->ToObjectUnchecked();
935 ASSERT(result != heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000936 // This might be called during the marking phase of the collector
937 // hence the unchecked cast.
938 return reinterpret_cast<Code*>(result);
939}
940
941
John Reck59135872010-11-02 12:39:01 -0700942MaybeObject* StubCache::ComputeCallInitialize(int argc,
943 InLoopFlag in_loop,
Ben Murdoch257744e2011-11-30 15:57:28 +0000944 RelocInfo::Mode mode,
John Reck59135872010-11-02 12:39:01 -0700945 Code::Kind kind) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000946 Code::ExtraICState extra_state =
947 CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
948 CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100949 Code::Flags flags = Code::ComputeFlags(kind,
950 in_loop,
951 UNINITIALIZED,
Ben Murdoch257744e2011-11-30 15:57:28 +0000952 extra_state,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100953 NORMAL,
954 argc);
John Reck59135872010-11-02 12:39:01 -0700955 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +0100956 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -0700957 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
958 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000959 if (!probe->IsUndefined()) return probe;
960 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +0100961 return FillCache(isolate_, compiler.CompileCallInitialize(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +0000962}
963
964
Ben Murdoch257744e2011-11-30 15:57:28 +0000965Handle<Code> StubCache::ComputeCallInitialize(int argc,
966 InLoopFlag in_loop,
967 RelocInfo::Mode mode) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800968 if (in_loop == IN_LOOP) {
969 // Force the creation of the corresponding stub outside loops,
970 // because it may be used when clearing the ICs later - it is
971 // possible for a series of IC transitions to lose the in-loop
972 // information, and the IC clearing code can't generate a stub
973 // that it needs so we need to ensure it is generated already.
Ben Murdoch257744e2011-11-30 15:57:28 +0000974 ComputeCallInitialize(argc, NOT_IN_LOOP, mode);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800975 }
Steve Block44f0eee2011-05-26 01:26:41 +0100976 CALL_HEAP_FUNCTION(isolate_,
Ben Murdoch257744e2011-11-30 15:57:28 +0000977 ComputeCallInitialize(argc, in_loop, mode, Code::CALL_IC),
978 Code);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800979}
980
981
982Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
983 InLoopFlag in_loop) {
984 if (in_loop == IN_LOOP) {
985 // Force the creation of the corresponding stub outside loops,
986 // because it may be used when clearing the ICs later - it is
987 // possible for a series of IC transitions to lose the in-loop
988 // information, and the IC clearing code can't generate a stub
989 // that it needs so we need to ensure it is generated already.
990 ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
991 }
992 CALL_HEAP_FUNCTION(
Steve Block44f0eee2011-05-26 01:26:41 +0100993 isolate_,
Ben Murdoch257744e2011-11-30 15:57:28 +0000994 ComputeCallInitialize(argc,
995 in_loop,
996 RelocInfo::CODE_TARGET,
997 Code::KEYED_CALL_IC),
998 Code);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800999}
1000
1001
Ben Murdoch257744e2011-11-30 15:57:28 +00001002MaybeObject* StubCache::ComputeCallPreMonomorphic(
1003 int argc,
1004 InLoopFlag in_loop,
1005 Code::Kind kind,
1006 Code::ExtraICState extra_ic_state) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001007 Code::Flags flags = Code::ComputeFlags(kind,
1008 in_loop,
1009 PREMONOMORPHIC,
Ben Murdoch257744e2011-11-30 15:57:28 +00001010 extra_ic_state,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001011 NORMAL,
1012 argc);
John Reck59135872010-11-02 12:39:01 -07001013 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +01001014 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -07001015 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1016 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001017 if (!probe->IsUndefined()) return probe;
1018 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +01001019 return FillCache(isolate_, compiler.CompileCallPreMonomorphic(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001020}
1021
1022
John Reck59135872010-11-02 12:39:01 -07001023MaybeObject* StubCache::ComputeCallNormal(int argc,
1024 InLoopFlag in_loop,
Ben Murdoch257744e2011-11-30 15:57:28 +00001025 Code::Kind kind,
1026 Code::ExtraICState extra_ic_state) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001027 Code::Flags flags = Code::ComputeFlags(kind,
1028 in_loop,
1029 MONOMORPHIC,
Ben Murdoch257744e2011-11-30 15:57:28 +00001030 extra_ic_state,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001031 NORMAL,
1032 argc);
John Reck59135872010-11-02 12:39:01 -07001033 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +01001034 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -07001035 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1036 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001037 if (!probe->IsUndefined()) return probe;
1038 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +01001039 return FillCache(isolate_, compiler.CompileCallNormal(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001040}
1041
1042
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001043MaybeObject* StubCache::ComputeCallArguments(int argc,
1044 InLoopFlag in_loop,
1045 Code::Kind kind) {
1046 ASSERT(kind == Code::KEYED_CALL_IC);
1047 Code::Flags flags = Code::ComputeFlags(kind,
1048 in_loop,
1049 MEGAMORPHIC,
1050 Code::kNoExtraICState,
1051 NORMAL,
1052 argc);
1053 Object* probe;
1054 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1055 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1056 }
1057 if (!probe->IsUndefined()) return probe;
1058 StubCompiler compiler;
1059 return FillCache(isolate_, compiler.CompileCallArguments(flags));
1060}
1061
1062
Ben Murdoch257744e2011-11-30 15:57:28 +00001063MaybeObject* StubCache::ComputeCallMegamorphic(
1064 int argc,
1065 InLoopFlag in_loop,
1066 Code::Kind kind,
1067 Code::ExtraICState extra_ic_state) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01001068 Code::Flags flags = Code::ComputeFlags(kind,
1069 in_loop,
1070 MEGAMORPHIC,
Ben Murdoch257744e2011-11-30 15:57:28 +00001071 extra_ic_state,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001072 NORMAL,
1073 argc);
John Reck59135872010-11-02 12:39:01 -07001074 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +01001075 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -07001076 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1077 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001078 if (!probe->IsUndefined()) return probe;
1079 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +01001080 return FillCache(isolate_, compiler.CompileCallMegamorphic(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001081}
1082
1083
Ben Murdoch257744e2011-11-30 15:57:28 +00001084MaybeObject* StubCache::ComputeCallMiss(int argc,
1085 Code::Kind kind,
1086 Code::ExtraICState extra_ic_state) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001087 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
1088 // and monomorphic stubs are not mixed up together in the stub cache.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001089 Code::Flags flags = Code::ComputeFlags(kind,
1090 NOT_IN_LOOP,
1091 MONOMORPHIC_PROTOTYPE_FAILURE,
Ben Murdoch257744e2011-11-30 15:57:28 +00001092 extra_ic_state,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001093 NORMAL,
1094 argc,
1095 OWN_MAP);
John Reck59135872010-11-02 12:39:01 -07001096 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +01001097 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -07001098 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1099 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001100 if (!probe->IsUndefined()) return probe;
1101 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +01001102 return FillCache(isolate_, compiler.CompileCallMiss(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001103}
1104
1105
1106#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdoch257744e2011-11-30 15:57:28 +00001107MaybeObject* StubCache::ComputeCallDebugBreak(
1108 int argc,
1109 Code::Kind kind) {
1110 // Extra IC state is irrelevant for debug break ICs. They jump to
1111 // the actual call ic to carry out the work.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001112 Code::Flags flags = Code::ComputeFlags(kind,
1113 NOT_IN_LOOP,
1114 DEBUG_BREAK,
1115 Code::kNoExtraICState,
1116 NORMAL,
1117 argc);
John Reck59135872010-11-02 12:39:01 -07001118 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +01001119 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -07001120 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1121 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001122 if (!probe->IsUndefined()) return probe;
1123 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +01001124 return FillCache(isolate_, compiler.CompileCallDebugBreak(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001125}
1126
1127
Ben Murdoch257744e2011-11-30 15:57:28 +00001128MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(
1129 int argc,
1130 Code::Kind kind) {
1131 // Extra IC state is irrelevant for debug break ICs. They jump to
1132 // the actual call ic to carry out the work.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001133 Code::Flags flags = Code::ComputeFlags(kind,
1134 NOT_IN_LOOP,
1135 DEBUG_PREPARE_STEP_IN,
1136 Code::kNoExtraICState,
1137 NORMAL,
1138 argc);
John Reck59135872010-11-02 12:39:01 -07001139 Object* probe;
Steve Block44f0eee2011-05-26 01:26:41 +01001140 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
John Reck59135872010-11-02 12:39:01 -07001141 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1142 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001143 if (!probe->IsUndefined()) return probe;
1144 StubCompiler compiler;
Steve Block44f0eee2011-05-26 01:26:41 +01001145 return FillCache(isolate_, compiler.CompileCallDebugPrepareStepIn(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001146}
1147#endif
1148
1149
Steve Blocka7e24c12009-10-30 11:49:00 +00001150void StubCache::Clear() {
1151 for (int i = 0; i < kPrimaryTableSize; i++) {
Steve Block44f0eee2011-05-26 01:26:41 +01001152 primary_[i].key = heap()->empty_string();
1153 primary_[i].value = isolate_->builtins()->builtin(
1154 Builtins::kIllegal);
Steve Blocka7e24c12009-10-30 11:49:00 +00001155 }
1156 for (int j = 0; j < kSecondaryTableSize; j++) {
Steve Block44f0eee2011-05-26 01:26:41 +01001157 secondary_[j].key = heap()->empty_string();
1158 secondary_[j].value = isolate_->builtins()->builtin(
1159 Builtins::kIllegal);
Steve Blocka7e24c12009-10-30 11:49:00 +00001160 }
1161}
1162
1163
Ben Murdochb0fe1622011-05-05 13:52:32 +01001164void StubCache::CollectMatchingMaps(ZoneMapList* types,
1165 String* name,
1166 Code::Flags flags) {
1167 for (int i = 0; i < kPrimaryTableSize; i++) {
1168 if (primary_[i].key == name) {
1169 Map* map = primary_[i].value->FindFirstMap();
1170 // Map can be NULL, if the stub is constant function call
1171 // with a primitive receiver.
1172 if (map == NULL) continue;
1173
1174 int offset = PrimaryOffset(name, flags, map);
1175 if (entry(primary_, offset) == &primary_[i]) {
1176 types->Add(Handle<Map>(map));
1177 }
1178 }
1179 }
1180
1181 for (int i = 0; i < kSecondaryTableSize; i++) {
1182 if (secondary_[i].key == name) {
1183 Map* map = secondary_[i].value->FindFirstMap();
1184 // Map can be NULL, if the stub is constant function call
1185 // with a primitive receiver.
1186 if (map == NULL) continue;
1187
1188 // Lookup in primary table and skip duplicates.
1189 int primary_offset = PrimaryOffset(name, flags, map);
1190 Entry* primary_entry = entry(primary_, primary_offset);
1191 if (primary_entry->key == name) {
1192 Map* primary_map = primary_entry->value->FindFirstMap();
1193 if (map == primary_map) continue;
1194 }
1195
1196 // Lookup in secondary table and add matches.
1197 int offset = SecondaryOffset(name, flags, primary_offset);
1198 if (entry(secondary_, offset) == &secondary_[i]) {
1199 types->Add(Handle<Map>(map));
1200 }
1201 }
1202 }
1203}
1204
1205
Steve Blocka7e24c12009-10-30 11:49:00 +00001206// ------------------------------------------------------------------------
1207// StubCompiler implementation.
1208
1209
Ben Murdoch8b112d22011-06-08 16:22:53 +01001210RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) {
Steve Blockd0582a62009-12-15 09:54:21 +00001211 ASSERT(args[0]->IsJSObject());
1212 ASSERT(args[1]->IsJSObject());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001213 AccessorInfo* callback = AccessorInfo::cast(args[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001214 Address getter_address = v8::ToCData<Address>(callback->getter());
1215 v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
1216 ASSERT(fun != NULL);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001217 v8::AccessorInfo info(&args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01001218 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001219 v8::Handle<v8::Value> result;
1220 {
1221 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001222 VMState state(isolate, EXTERNAL);
1223 ExternalCallbackScope call_scope(isolate, getter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001224 result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
1225 }
Steve Block44f0eee2011-05-26 01:26:41 +01001226 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1227 if (result.IsEmpty()) return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001228 return *v8::Utils::OpenHandle(*result);
1229}
1230
1231
Ben Murdoch8b112d22011-06-08 16:22:53 +01001232RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001233 JSObject* recv = JSObject::cast(args[0]);
1234 AccessorInfo* callback = AccessorInfo::cast(args[1]);
1235 Address setter_address = v8::ToCData<Address>(callback->setter());
1236 v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
1237 ASSERT(fun != NULL);
1238 Handle<String> name = args.at<String>(2);
1239 Handle<Object> value = args.at<Object>(3);
Steve Block44f0eee2011-05-26 01:26:41 +01001240 HandleScope scope(isolate);
1241 LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
1242 CustomArguments custom_args(isolate, callback->data(), recv, recv);
Steve Blocka7e24c12009-10-30 11:49:00 +00001243 v8::AccessorInfo info(custom_args.end());
1244 {
1245 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001246 VMState state(isolate, EXTERNAL);
1247 ExternalCallbackScope call_scope(isolate, setter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001248 fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
1249 }
Steve Block44f0eee2011-05-26 01:26:41 +01001250 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001251 return *value;
1252}
1253
Steve Block6ded16b2010-05-10 14:33:55 +01001254
1255static const int kAccessorInfoOffsetInInterceptorArgs = 2;
1256
1257
Steve Blocka7e24c12009-10-30 11:49:00 +00001258/**
1259 * Attempts to load a property with an interceptor (which must be present),
1260 * but doesn't search the prototype chain.
1261 *
1262 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
1263 * provide any value for the given name.
1264 */
Ben Murdoch8b112d22011-06-08 16:22:53 +01001265RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
Steve Block6ded16b2010-05-10 14:33:55 +01001266 Handle<String> name_handle = args.at<String>(0);
1267 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
1268 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1269 ASSERT(args[2]->IsJSObject()); // Receiver.
1270 ASSERT(args[3]->IsJSObject()); // Holder.
1271 ASSERT(args.length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001272
1273 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1274 v8::NamedPropertyGetter getter =
1275 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1276 ASSERT(getter != NULL);
1277
1278 {
1279 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001280 v8::AccessorInfo info(args.arguments() -
1281 kAccessorInfoOffsetInInterceptorArgs);
Steve Block44f0eee2011-05-26 01:26:41 +01001282 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001283 v8::Handle<v8::Value> r;
1284 {
1285 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001286 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001287 r = getter(v8::Utils::ToLocal(name_handle), info);
1288 }
Steve Block44f0eee2011-05-26 01:26:41 +01001289 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001290 if (!r.IsEmpty()) {
1291 return *v8::Utils::OpenHandle(*r);
1292 }
1293 }
1294
Steve Block44f0eee2011-05-26 01:26:41 +01001295 return isolate->heap()->no_interceptor_result_sentinel();
Steve Blocka7e24c12009-10-30 11:49:00 +00001296}
1297
1298
John Reck59135872010-11-02 12:39:01 -07001299static MaybeObject* ThrowReferenceError(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001300 // If the load is non-contextual, just return the undefined result.
1301 // Note that both keyed and non-keyed loads may end up here, so we
1302 // can't use either LoadIC or KeyedLoadIC constructors.
Steve Block44f0eee2011-05-26 01:26:41 +01001303 IC ic(IC::NO_EXTRA_FRAME, Isolate::Current());
Steve Blocka7e24c12009-10-30 11:49:00 +00001304 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01001305 if (!ic.SlowIsContextual()) return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001306
1307 // Throw a reference error.
1308 HandleScope scope;
1309 Handle<String> name_handle(name);
1310 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01001311 FACTORY->NewReferenceError("not_defined",
Steve Blocka7e24c12009-10-30 11:49:00 +00001312 HandleVector(&name_handle, 1));
Steve Block44f0eee2011-05-26 01:26:41 +01001313 return Isolate::Current()->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00001314}
1315
1316
John Reck59135872010-11-02 12:39:01 -07001317static MaybeObject* LoadWithInterceptor(Arguments* args,
1318 PropertyAttributes* attrs) {
Steve Block6ded16b2010-05-10 14:33:55 +01001319 Handle<String> name_handle = args->at<String>(0);
1320 Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
1321 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1322 Handle<JSObject> receiver_handle = args->at<JSObject>(2);
1323 Handle<JSObject> holder_handle = args->at<JSObject>(3);
1324 ASSERT(args->length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001325
Steve Block44f0eee2011-05-26 01:26:41 +01001326 Isolate* isolate = receiver_handle->GetIsolate();
1327
Steve Blocka7e24c12009-10-30 11:49:00 +00001328 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1329 v8::NamedPropertyGetter getter =
1330 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1331 ASSERT(getter != NULL);
1332
1333 {
1334 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001335 v8::AccessorInfo info(args->arguments() -
1336 kAccessorInfoOffsetInInterceptorArgs);
Steve Block44f0eee2011-05-26 01:26:41 +01001337 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001338 v8::Handle<v8::Value> r;
1339 {
1340 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001341 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001342 r = getter(v8::Utils::ToLocal(name_handle), info);
1343 }
Steve Block44f0eee2011-05-26 01:26:41 +01001344 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001345 if (!r.IsEmpty()) {
1346 *attrs = NONE;
1347 return *v8::Utils::OpenHandle(*r);
1348 }
1349 }
1350
John Reck59135872010-11-02 12:39:01 -07001351 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00001352 *receiver_handle,
1353 *name_handle,
1354 attrs);
Steve Block44f0eee2011-05-26 01:26:41 +01001355 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001356 return result;
1357}
1358
1359
1360/**
1361 * Loads a property with an interceptor performing post interceptor
1362 * lookup if interceptor failed.
1363 */
Ben Murdoch8b112d22011-06-08 16:22:53 +01001364RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001365 PropertyAttributes attr = NONE;
John Reck59135872010-11-02 12:39:01 -07001366 Object* result;
1367 { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
1368 if (!maybe_result->ToObject(&result)) return maybe_result;
1369 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001370
1371 // If the property is present, return it.
1372 if (attr != ABSENT) return result;
Steve Block6ded16b2010-05-10 14:33:55 +01001373 return ThrowReferenceError(String::cast(args[0]));
Steve Blocka7e24c12009-10-30 11:49:00 +00001374}
1375
1376
Ben Murdoch8b112d22011-06-08 16:22:53 +01001377RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001378 PropertyAttributes attr;
John Reck59135872010-11-02 12:39:01 -07001379 MaybeObject* result = LoadWithInterceptor(&args, &attr);
Steve Block44f0eee2011-05-26 01:26:41 +01001380 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001381 // This is call IC. In this case, we simply return the undefined result which
1382 // will lead to an exception when trying to invoke the result as a
1383 // function.
1384 return result;
1385}
1386
1387
Ben Murdoch8b112d22011-06-08 16:22:53 +01001388RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001389 ASSERT(args.length() == 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001390 JSObject* recv = JSObject::cast(args[0]);
1391 String* name = String::cast(args[1]);
1392 Object* value = args[2];
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001393 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001394 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001395 ASSERT(recv->HasNamedInterceptor());
1396 PropertyAttributes attr = NONE;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001397 MaybeObject* result = recv->SetPropertyWithInterceptor(
1398 name, value, attr, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001399 return result;
1400}
1401
1402
Ben Murdoch8b112d22011-06-08 16:22:53 +01001403RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001404 JSObject* receiver = JSObject::cast(args[0]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001405 ASSERT(args.smi_at(1) >= 0);
1406 uint32_t index = args.smi_at(1);
Andrei Popescu402d9372010-02-26 13:31:12 +00001407 return receiver->GetElementWithInterceptor(receiver, index);
1408}
1409
1410
John Reck59135872010-11-02 12:39:01 -07001411MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001412 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001413 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001414 Code::Kind kind = Code::ExtractKindFromFlags(flags);
Ben Murdoch257744e2011-11-30 15:57:28 +00001415 Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001416 if (kind == Code::CALL_IC) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001417 CallIC::GenerateInitialize(masm(), argc, extra_ic_state);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001418 } else {
1419 KeyedCallIC::GenerateInitialize(masm(), argc);
1420 }
John Reck59135872010-11-02 12:39:01 -07001421 Object* result;
1422 { MaybeObject* maybe_result =
1423 GetCodeWithFlags(flags, "CompileCallInitialize");
1424 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001425 }
Steve Block44f0eee2011-05-26 01:26:41 +01001426 isolate()->counters()->call_initialize_stubs()->Increment();
John Reck59135872010-11-02 12:39:01 -07001427 Code* code = Code::cast(result);
1428 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001429 PROFILE(isolate(),
1430 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
John Reck59135872010-11-02 12:39:01 -07001431 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001432 GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001433 return result;
1434}
1435
1436
John Reck59135872010-11-02 12:39:01 -07001437MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001438 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001439 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1440 // The code of the PreMonomorphic stub is the same as the code
1441 // of the Initialized stub. They just differ on the code object flags.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001442 Code::Kind kind = Code::ExtractKindFromFlags(flags);
Ben Murdoch257744e2011-11-30 15:57:28 +00001443 Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001444 if (kind == Code::CALL_IC) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001445 CallIC::GenerateInitialize(masm(), argc, extra_ic_state);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001446 } else {
1447 KeyedCallIC::GenerateInitialize(masm(), argc);
1448 }
John Reck59135872010-11-02 12:39:01 -07001449 Object* result;
1450 { MaybeObject* maybe_result =
1451 GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1452 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001453 }
Steve Block44f0eee2011-05-26 01:26:41 +01001454 isolate()->counters()->call_premonomorphic_stubs()->Increment();
John Reck59135872010-11-02 12:39:01 -07001455 Code* code = Code::cast(result);
1456 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001457 PROFILE(isolate(),
1458 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
John Reck59135872010-11-02 12:39:01 -07001459 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001460 GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001461 return result;
1462}
1463
1464
John Reck59135872010-11-02 12:39:01 -07001465MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001466 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001467 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001468 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1469 if (kind == Code::CALL_IC) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001470 // Call normal is always with a explict receiver.
1471 ASSERT(!CallIC::Contextual::decode(
1472 Code::ExtractExtraICStateFromFlags(flags)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001473 CallIC::GenerateNormal(masm(), argc);
1474 } else {
1475 KeyedCallIC::GenerateNormal(masm(), argc);
1476 }
John Reck59135872010-11-02 12:39:01 -07001477 Object* result;
1478 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallNormal");
1479 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001480 }
Steve Block44f0eee2011-05-26 01:26:41 +01001481 isolate()->counters()->call_normal_stubs()->Increment();
John Reck59135872010-11-02 12:39:01 -07001482 Code* code = Code::cast(result);
1483 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001484 PROFILE(isolate(),
1485 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
John Reck59135872010-11-02 12:39:01 -07001486 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001487 GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001488 return result;
1489}
1490
1491
John Reck59135872010-11-02 12:39:01 -07001492MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001493 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001494 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001495 Code::Kind kind = Code::ExtractKindFromFlags(flags);
Ben Murdoch257744e2011-11-30 15:57:28 +00001496 Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001497 if (kind == Code::CALL_IC) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001498 CallIC::GenerateMegamorphic(masm(), argc, extra_ic_state);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001499 } else {
1500 KeyedCallIC::GenerateMegamorphic(masm(), argc);
1501 }
John Reck59135872010-11-02 12:39:01 -07001502 Object* result;
1503 { MaybeObject* maybe_result =
1504 GetCodeWithFlags(flags, "CompileCallMegamorphic");
1505 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001506 }
Steve Block44f0eee2011-05-26 01:26:41 +01001507 isolate()->counters()->call_megamorphic_stubs()->Increment();
John Reck59135872010-11-02 12:39:01 -07001508 Code* code = Code::cast(result);
1509 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001510 PROFILE(isolate(),
1511 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
John Reck59135872010-11-02 12:39:01 -07001512 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001513 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001514 return result;
1515}
1516
1517
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001518MaybeObject* StubCompiler::CompileCallArguments(Code::Flags flags) {
1519 HandleScope scope(isolate());
1520 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1521 KeyedCallIC::GenerateNonStrictArguments(masm(), argc);
1522 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1523 Object* result;
1524 { MaybeObject* maybe_result =
1525 GetCodeWithFlags(flags, "CompileCallArguments");
1526 if (!maybe_result->ToObject(&result)) return maybe_result;
1527 }
1528 Code* code = Code::cast(result);
1529 USE(code);
1530 PROFILE(isolate(),
1531 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
1532 code, code->arguments_count()));
1533 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
1534 return result;
1535}
1536
1537
John Reck59135872010-11-02 12:39:01 -07001538MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001539 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001540 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001541 Code::Kind kind = Code::ExtractKindFromFlags(flags);
Ben Murdoch257744e2011-11-30 15:57:28 +00001542 Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001543 if (kind == Code::CALL_IC) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001544 CallIC::GenerateMiss(masm(), argc, extra_ic_state);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001545 } else {
1546 KeyedCallIC::GenerateMiss(masm(), argc);
1547 }
John Reck59135872010-11-02 12:39:01 -07001548 Object* result;
1549 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallMiss");
1550 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001551 }
Steve Block44f0eee2011-05-26 01:26:41 +01001552 isolate()->counters()->call_megamorphic_stubs()->Increment();
John Reck59135872010-11-02 12:39:01 -07001553 Code* code = Code::cast(result);
1554 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001555 PROFILE(isolate(),
1556 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
John Reck59135872010-11-02 12:39:01 -07001557 code, code->arguments_count()));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001558 GDBJIT(AddCode(GDBJITInterface::CALL_MISS, Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001559 return result;
1560}
1561
1562
1563#ifdef ENABLE_DEBUGGER_SUPPORT
John Reck59135872010-11-02 12:39:01 -07001564MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001565 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001566 Debug::GenerateCallICDebugBreak(masm());
John Reck59135872010-11-02 12:39:01 -07001567 Object* result;
1568 { MaybeObject* maybe_result =
1569 GetCodeWithFlags(flags, "CompileCallDebugBreak");
1570 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001571 }
John Reck59135872010-11-02 12:39:01 -07001572 Code* code = Code::cast(result);
1573 USE(code);
1574 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1575 USE(kind);
Steve Block44f0eee2011-05-26 01:26:41 +01001576 PROFILE(isolate(),
1577 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
John Reck59135872010-11-02 12:39:01 -07001578 code, code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001579 return result;
1580}
1581
1582
John Reck59135872010-11-02 12:39:01 -07001583MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01001584 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001585 // Use the same code for the the step in preparations as we do for
1586 // the miss case.
1587 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001588 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1589 if (kind == Code::CALL_IC) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001590 // For the debugger extra ic state is irrelevant.
1591 CallIC::GenerateMiss(masm(), argc, Code::kNoExtraICState);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001592 } else {
1593 KeyedCallIC::GenerateMiss(masm(), argc);
1594 }
John Reck59135872010-11-02 12:39:01 -07001595 Object* result;
1596 { MaybeObject* maybe_result =
1597 GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1598 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001599 }
John Reck59135872010-11-02 12:39:01 -07001600 Code* code = Code::cast(result);
1601 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001602 PROFILE(isolate(),
1603 CodeCreateEvent(
1604 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1605 code,
1606 code->arguments_count()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001607 return result;
1608}
1609#endif
1610
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001611#undef CALL_LOGGER_TAG
Steve Blocka7e24c12009-10-30 11:49:00 +00001612
John Reck59135872010-11-02 12:39:01 -07001613MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags,
1614 const char* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001615 // Check for allocation failures during stub compilation.
1616 if (failure_->IsFailure()) return failure_;
1617
1618 // Create code object in the heap.
1619 CodeDesc desc;
1620 masm_.GetCode(&desc);
Steve Block44f0eee2011-05-26 01:26:41 +01001621 MaybeObject* result = heap()->CreateCode(desc, flags, masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +00001622#ifdef ENABLE_DISASSEMBLER
1623 if (FLAG_print_code_stubs && !result->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07001624 Code::cast(result->ToObjectUnchecked())->Disassemble(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001625 }
1626#endif
1627 return result;
1628}
1629
1630
John Reck59135872010-11-02 12:39:01 -07001631MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001632 if (FLAG_print_code_stubs && (name != NULL)) {
1633 return GetCodeWithFlags(flags, *name->ToCString());
1634 }
1635 return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1636}
1637
Andrei Popescu402d9372010-02-26 13:31:12 +00001638
Leon Clarke4515c472010-02-03 11:58:03 +00001639void StubCompiler::LookupPostInterceptor(JSObject* holder,
1640 String* name,
1641 LookupResult* lookup) {
1642 holder->LocalLookupRealNamedProperty(name, lookup);
Andrei Popescu402d9372010-02-26 13:31:12 +00001643 if (!lookup->IsProperty()) {
1644 lookup->NotFound();
Leon Clarke4515c472010-02-03 11:58:03 +00001645 Object* proto = holder->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001646 if (!proto->IsNull()) {
Leon Clarke4515c472010-02-03 11:58:03 +00001647 proto->Lookup(name, lookup);
1648 }
1649 }
1650}
1651
1652
Steve Blocka7e24c12009-10-30 11:49:00 +00001653
John Reck59135872010-11-02 12:39:01 -07001654MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001655 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
John Reck59135872010-11-02 12:39:01 -07001656 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001657 if (!result->IsFailure()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001658 PROFILE(isolate(),
1659 CodeCreateEvent(Logger::LOAD_IC_TAG,
John Reck59135872010-11-02 12:39:01 -07001660 Code::cast(result->ToObjectUnchecked()),
1661 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001662 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1663 name,
1664 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001665 }
1666 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001667}
1668
1669
Ben Murdoch257744e2011-11-30 15:57:28 +00001670MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type,
1671 String* name,
1672 InlineCacheState state) {
1673 Code::Flags flags = Code::ComputeFlags(
1674 Code::KEYED_LOAD_IC, NOT_IN_LOOP, state, Code::kNoExtraICState, type);
John Reck59135872010-11-02 12:39:01 -07001675 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001676 if (!result->IsFailure()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001677 PROFILE(isolate(),
1678 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
John Reck59135872010-11-02 12:39:01 -07001679 Code::cast(result->ToObjectUnchecked()),
1680 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001681 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1682 name,
1683 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001684 }
1685 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001686}
1687
1688
John Reck59135872010-11-02 12:39:01 -07001689MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001690 Code::Flags flags = Code::ComputeMonomorphicFlags(
1691 Code::STORE_IC, type, strict_mode_);
John Reck59135872010-11-02 12:39:01 -07001692 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001693 if (!result->IsFailure()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001694 PROFILE(isolate(),
1695 CodeCreateEvent(Logger::STORE_IC_TAG,
John Reck59135872010-11-02 12:39:01 -07001696 Code::cast(result->ToObjectUnchecked()),
1697 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001698 GDBJIT(AddCode(GDBJITInterface::STORE_IC,
1699 name,
1700 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001701 }
1702 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001703}
1704
1705
Ben Murdoch257744e2011-11-30 15:57:28 +00001706MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type,
1707 String* name,
1708 InlineCacheState state) {
1709 Code::Flags flags = Code::ComputeFlags(
1710 Code::KEYED_STORE_IC, NOT_IN_LOOP, state, strict_mode_, type);
John Reck59135872010-11-02 12:39:01 -07001711 MaybeObject* result = GetCodeWithFlags(flags, name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001712 if (!result->IsFailure()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001713 PROFILE(isolate(),
1714 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
John Reck59135872010-11-02 12:39:01 -07001715 Code::cast(result->ToObjectUnchecked()),
1716 name));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001717 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC,
1718 name,
1719 Code::cast(result->ToObjectUnchecked())));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001720 }
1721 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001722}
1723
1724
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001725void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
1726 MacroAssembler* masm) {
1727 KeyedStoreIC::GenerateSlow(masm);
1728}
1729
1730
Steve Block8defd9f2010-07-08 12:39:36 +01001731CallStubCompiler::CallStubCompiler(int argc,
1732 InLoopFlag in_loop,
1733 Code::Kind kind,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001734 Code::ExtraICState extra_ic_state,
Steve Block8defd9f2010-07-08 12:39:36 +01001735 InlineCacheHolderFlag cache_holder)
Ben Murdochb8e0da22011-05-16 14:20:40 +01001736 : arguments_(argc),
1737 in_loop_(in_loop),
1738 kind_(kind),
1739 extra_ic_state_(extra_ic_state),
1740 cache_holder_(cache_holder) {
Steve Block8defd9f2010-07-08 12:39:36 +01001741}
1742
1743
Steve Block44f0eee2011-05-26 01:26:41 +01001744bool CallStubCompiler::HasCustomCallGenerator(JSFunction* function) {
1745 SharedFunctionInfo* info = function->shared();
1746 if (info->HasBuiltinFunctionId()) {
1747 BuiltinFunctionId id = info->builtin_function_id();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001748#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
Steve Block44f0eee2011-05-26 01:26:41 +01001749 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
Ben Murdochb0fe1622011-05-05 13:52:32 +01001750#undef CALL_GENERATOR_CASE
Steve Block44f0eee2011-05-26 01:26:41 +01001751 }
1752 CallOptimization optimization(function);
1753 if (optimization.is_simple_api_call()) {
1754 return true;
1755 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001756 return false;
1757}
1758
1759
Steve Block44f0eee2011-05-26 01:26:41 +01001760MaybeObject* CallStubCompiler::CompileCustomCall(Object* object,
John Reck59135872010-11-02 12:39:01 -07001761 JSObject* holder,
1762 JSGlobalPropertyCell* cell,
1763 JSFunction* function,
1764 String* fname) {
Steve Block44f0eee2011-05-26 01:26:41 +01001765 ASSERT(HasCustomCallGenerator(function));
1766
1767 SharedFunctionInfo* info = function->shared();
1768 if (info->HasBuiltinFunctionId()) {
1769 BuiltinFunctionId id = info->builtin_function_id();
1770#define CALL_GENERATOR_CASE(name) \
1771 if (id == k##name) { \
1772 return CallStubCompiler::Compile##name##Call(object, \
1773 holder, \
1774 cell, \
1775 function, \
1776 fname); \
1777 }
1778 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
Ben Murdochb0fe1622011-05-05 13:52:32 +01001779#undef CALL_GENERATOR_CASE
Steve Block44f0eee2011-05-26 01:26:41 +01001780 }
1781 CallOptimization optimization(function);
1782 ASSERT(optimization.is_simple_api_call());
1783 return CompileFastApiCall(optimization,
1784 object,
1785 holder,
1786 cell,
1787 function,
1788 fname);
Kristian Monsen25f61362010-05-21 11:50:48 +01001789}
1790
1791
John Reck59135872010-11-02 12:39:01 -07001792MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001793 int argc = arguments_.immediate();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001794 Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001795 type,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001796 extra_ic_state_,
Steve Block8defd9f2010-07-08 12:39:36 +01001797 cache_holder_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001798 in_loop_,
1799 argc);
1800 return GetCodeWithFlags(flags, name);
1801}
1802
1803
John Reck59135872010-11-02 12:39:01 -07001804MaybeObject* CallStubCompiler::GetCode(JSFunction* function) {
Kristian Monsen25f61362010-05-21 11:50:48 +01001805 String* function_name = NULL;
1806 if (function->shared()->name()->IsString()) {
1807 function_name = String::cast(function->shared()->name());
1808 }
1809 return GetCode(CONSTANT_FUNCTION, function_name);
1810}
1811
1812
John Reck59135872010-11-02 12:39:01 -07001813MaybeObject* ConstructStubCompiler::GetCode() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001814 Code::Flags flags = Code::ComputeFlags(Code::STUB);
John Reck59135872010-11-02 12:39:01 -07001815 Object* result;
1816 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ConstructStub");
1817 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001818 }
John Reck59135872010-11-02 12:39:01 -07001819 Code* code = Code::cast(result);
1820 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001821 PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
Ben Murdochb8e0da22011-05-16 14:20:40 +01001822 GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001823 return result;
1824}
1825
1826
Steve Block6ded16b2010-05-10 14:33:55 +01001827CallOptimization::CallOptimization(LookupResult* lookup) {
1828 if (!lookup->IsProperty() || !lookup->IsCacheable() ||
1829 lookup->type() != CONSTANT_FUNCTION) {
1830 Initialize(NULL);
1831 } else {
1832 // We only optimize constant function calls.
1833 Initialize(lookup->GetConstantFunction());
1834 }
1835}
1836
1837CallOptimization::CallOptimization(JSFunction* function) {
1838 Initialize(function);
1839}
1840
1841
1842int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
1843 JSObject* holder) const {
1844 ASSERT(is_simple_api_call_);
1845 if (expected_receiver_type_ == NULL) return 0;
1846 int depth = 0;
1847 while (object != holder) {
1848 if (object->IsInstanceOf(expected_receiver_type_)) return depth;
1849 object = JSObject::cast(object->GetPrototype());
1850 ++depth;
1851 }
1852 if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
1853 return kInvalidProtoDepth;
1854}
1855
1856
1857void CallOptimization::Initialize(JSFunction* function) {
1858 constant_function_ = NULL;
1859 is_simple_api_call_ = false;
1860 expected_receiver_type_ = NULL;
1861 api_call_info_ = NULL;
1862
1863 if (function == NULL || !function->is_compiled()) return;
1864
1865 constant_function_ = function;
1866 AnalyzePossibleApiFunction(function);
1867}
1868
1869
1870void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
1871 SharedFunctionInfo* sfi = function->shared();
1872 if (!sfi->IsApiFunction()) return;
1873 FunctionTemplateInfo* info = sfi->get_api_func_data();
1874
1875 // Require a C++ callback.
1876 if (info->call_code()->IsUndefined()) return;
1877 api_call_info_ = CallHandlerInfo::cast(info->call_code());
1878
1879 // Accept signatures that either have no restrictions at all or
1880 // only have restrictions on the receiver.
1881 if (!info->signature()->IsUndefined()) {
1882 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1883 if (!signature->args()->IsUndefined()) return;
1884 if (!signature->receiver()->IsUndefined()) {
1885 expected_receiver_type_ =
1886 FunctionTemplateInfo::cast(signature->receiver());
1887 }
1888 }
1889
1890 is_simple_api_call_ = true;
1891}
1892
1893
Steve Blocka7e24c12009-10-30 11:49:00 +00001894} } // namespace v8::internal