blob: cdb4874fcb81a220cb0db03676c7b2260b8ed42c [file] [log] [blame]
Ben Murdoch85b71792012-04-11 18:30:58 +01001// 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 Murdoch69a99ed2011-11-30 16:03:39 +000032#include "ast.h"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000033#include "code-stubs.h"
Ben Murdochb8e0da22011-05-16 14:20:40 +010034#include "gdb-jit.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000035#include "ic-inl.h"
36#include "stub-cache.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010037#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000038
39namespace v8 {
40namespace internal {
41
42// -----------------------------------------------------------------------
43// StubCache implementation.
44
45
Steve Block44f0eee2011-05-26 01:26:41 +010046StubCache::StubCache(Isolate* isolate) : isolate_(isolate) {
47 ASSERT(isolate == Isolate::Current());
Ben Murdoch85b71792012-04-11 18:30:58 +010048 memset(primary_, 0, sizeof(primary_[0]) * StubCache::kPrimaryTableSize);
49 memset(secondary_, 0, sizeof(secondary_[0]) * StubCache::kSecondaryTableSize);
Steve Block44f0eee2011-05-26 01:26:41 +010050}
51
Steve Blocka7e24c12009-10-30 11:49:00 +000052
Ben Murdoch85b71792012-04-11 18:30:58 +010053void StubCache::Initialize(bool create_heap_objects) {
Steve Blocka7e24c12009-10-30 11:49:00 +000054 ASSERT(IsPowerOf2(kPrimaryTableSize));
55 ASSERT(IsPowerOf2(kSecondaryTableSize));
Ben Murdoch85b71792012-04-11 18:30:58 +010056 if (create_heap_objects) {
57 HandleScope scope;
58 Clear();
59 }
Steve Blocka7e24c12009-10-30 11:49:00 +000060}
61
62
63Code* StubCache::Set(String* name, Map* map, Code* code) {
64 // Get the flags from the code.
65 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
66
67 // Validate that the name does not move on scavenge, and that we
68 // can use identity checks instead of string equality checks.
Steve Block44f0eee2011-05-26 01:26:41 +010069 ASSERT(!heap()->InNewSpace(name));
Steve Blocka7e24c12009-10-30 11:49:00 +000070 ASSERT(name->IsSymbol());
71
72 // The state bits are not important to the hash function because
73 // the stub cache only contains monomorphic stubs. Make sure that
74 // the bits are the least significant so they will be the ones
75 // masked out.
76 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
Ben Murdoch589d6972011-11-30 16:04:58 +000077 STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000078
79 // Make sure that the code type is not included in the hash.
80 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
81
82 // Compute the primary entry.
83 int primary_offset = PrimaryOffset(name, flags, map);
84 Entry* primary = entry(primary_, primary_offset);
Ben Murdoch85b71792012-04-11 18:30:58 +010085 Code* hit = primary->value;
Steve Blocka7e24c12009-10-30 11:49:00 +000086
87 // If the primary entry has useful data in it, we retire it to the
88 // secondary cache before overwriting it.
Ben Murdoch85b71792012-04-11 18:30:58 +010089 if (hit != isolate_->builtins()->builtin(Builtins::kIllegal)) {
90 Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
91 int secondary_offset =
92 SecondaryOffset(primary->key, primary_flags, primary_offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000093 Entry* secondary = entry(secondary_, secondary_offset);
94 *secondary = *primary;
95 }
96
97 // Update primary cache.
98 primary->key = name;
99 primary->value = code;
100 return code;
101}
102
103
Ben Murdoch85b71792012-04-11 18:30:58 +0100104MaybeObject* StubCache::ComputeLoadNonexistent(String* name,
105 JSObject* receiver) {
Steve Block8defd9f2010-07-08 12:39:36 +0100106 ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
Steve Block6ded16b2010-05-10 14:33:55 +0100107 // If no global objects are present in the prototype chain, the load
108 // nonexistent IC stub can be shared for all names for a given map
109 // and we use the empty string for the map cache in that case. If
110 // there are global objects involved, we need to check global
111 // property cells in the stub and therefore the stub will be
112 // specific to the name.
Ben Murdoch85b71792012-04-11 18:30:58 +0100113 String* cache_name = heap()->empty_string();
Steve Block6ded16b2010-05-10 14:33:55 +0100114 if (receiver->IsGlobalObject()) cache_name = name;
Ben Murdoch85b71792012-04-11 18:30:58 +0100115 JSObject* last = receiver;
Steve Block44f0eee2011-05-26 01:26:41 +0100116 while (last->GetPrototype() != heap()->null_value()) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100117 last = JSObject::cast(last->GetPrototype());
Steve Block6ded16b2010-05-10 14:33:55 +0100118 if (last->IsGlobalObject()) cache_name = name;
119 }
120 // Compile the stub that is either shared for all names or
121 // name specific if there are global objects involved.
122 Code::Flags flags =
123 Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
Ben Murdoch85b71792012-04-11 18:30:58 +0100124 Object* code = receiver->map()->FindInCodeCache(cache_name, flags);
125 if (code->IsUndefined()) {
126 LoadStubCompiler compiler;
127 { MaybeObject* maybe_code =
128 compiler.CompileLoadNonexistent(cache_name, receiver, last);
129 if (!maybe_code->ToObject(&code)) return maybe_code;
130 }
131 PROFILE(isolate_,
132 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name));
133 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, cache_name, Code::cast(code)));
134 Object* result;
135 { MaybeObject* maybe_result =
136 receiver->UpdateMapCodeCache(cache_name, Code::cast(code));
137 if (!maybe_result->ToObject(&result)) return maybe_result;
138 }
139 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100140 return code;
Steve Block6ded16b2010-05-10 14:33:55 +0100141}
142
143
Ben Murdoch85b71792012-04-11 18:30:58 +0100144MaybeObject* StubCache::ComputeLoadField(String* name,
145 JSObject* receiver,
146 JSObject* holder,
John Reck59135872010-11-02 12:39:01 -0700147 int field_index) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100148 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000149 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
Ben Murdoch85b71792012-04-11 18:30:58 +0100150 Object* code = receiver->map()->FindInCodeCache(name, flags);
151 if (code->IsUndefined()) {
152 LoadStubCompiler compiler;
153 { MaybeObject* maybe_code =
154 compiler.CompileLoadField(receiver, holder, field_index, name);
155 if (!maybe_code->ToObject(&code)) return maybe_code;
156 }
157 PROFILE(isolate_,
158 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
159 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
160 Object* result;
161 { MaybeObject* maybe_result =
162 receiver->UpdateMapCodeCache(name, Code::cast(code));
163 if (!maybe_result->ToObject(&result)) return maybe_result;
164 }
165 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100166 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000167}
168
169
Ben Murdoch85b71792012-04-11 18:30:58 +0100170MaybeObject* StubCache::ComputeLoadCallback(String* name,
171 JSObject* receiver,
172 JSObject* holder,
173 AccessorInfo* callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000174 ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
Ben Murdoch85b71792012-04-11 18:30:58 +0100175 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000176 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
Ben Murdoch85b71792012-04-11 18:30:58 +0100177 Object* code = receiver->map()->FindInCodeCache(name, flags);
178 if (code->IsUndefined()) {
179 LoadStubCompiler compiler;
180 { MaybeObject* maybe_code =
181 compiler.CompileLoadCallback(name, receiver, holder, callback);
182 if (!maybe_code->ToObject(&code)) return maybe_code;
183 }
184 PROFILE(isolate_,
185 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
186 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
187 Object* result;
188 { MaybeObject* maybe_result =
189 receiver->UpdateMapCodeCache(name, Code::cast(code));
190 if (!maybe_result->ToObject(&result)) return maybe_result;
191 }
192 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100193 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000194}
195
196
Ben Murdoch85b71792012-04-11 18:30:58 +0100197MaybeObject* StubCache::ComputeLoadConstant(String* name,
198 JSObject* receiver,
199 JSObject* holder,
200 Object* value) {
201 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000202 Code::Flags flags =
203 Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
Ben Murdoch85b71792012-04-11 18:30:58 +0100204 Object* code = receiver->map()->FindInCodeCache(name, flags);
205 if (code->IsUndefined()) {
206 LoadStubCompiler compiler;
207 { MaybeObject* maybe_code =
208 compiler.CompileLoadConstant(receiver, holder, value, name);
209 if (!maybe_code->ToObject(&code)) return maybe_code;
210 }
211 PROFILE(isolate_,
212 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
213 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
214 Object* result;
215 { MaybeObject* maybe_result =
216 receiver->UpdateMapCodeCache(name, Code::cast(code));
217 if (!maybe_result->ToObject(&result)) return maybe_result;
218 }
219 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100220 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000221}
222
223
Ben Murdoch85b71792012-04-11 18:30:58 +0100224MaybeObject* StubCache::ComputeLoadInterceptor(String* name,
225 JSObject* receiver,
226 JSObject* holder) {
227 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
Ben Murdoch85b71792012-04-11 18:30:58 +0100229 Object* code = receiver->map()->FindInCodeCache(name, flags);
230 if (code->IsUndefined()) {
231 LoadStubCompiler compiler;
232 { MaybeObject* maybe_code =
233 compiler.CompileLoadInterceptor(receiver, holder, name);
234 if (!maybe_code->ToObject(&code)) return maybe_code;
235 }
236 PROFILE(isolate_,
237 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
238 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
239 Object* result;
240 { MaybeObject* maybe_result =
241 receiver->UpdateMapCodeCache(name, Code::cast(code));
242 if (!maybe_result->ToObject(&result)) return maybe_result;
243 }
244 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100245 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000246}
247
248
Ben Murdoch85b71792012-04-11 18:30:58 +0100249MaybeObject* StubCache::ComputeLoadNormal() {
250 return isolate_->builtins()->builtin(Builtins::kLoadIC_Normal);
Steve Blocka7e24c12009-10-30 11:49:00 +0000251}
252
253
Ben Murdoch85b71792012-04-11 18:30:58 +0100254MaybeObject* StubCache::ComputeLoadGlobal(String* name,
255 JSObject* receiver,
256 GlobalObject* holder,
257 JSGlobalPropertyCell* cell,
John Reck59135872010-11-02 12:39:01 -0700258 bool is_dont_delete) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100259 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000260 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
Ben Murdoch85b71792012-04-11 18:30:58 +0100261 Object* code = receiver->map()->FindInCodeCache(name, flags);
262 if (code->IsUndefined()) {
263 LoadStubCompiler compiler;
264 { MaybeObject* maybe_code = compiler.CompileLoadGlobal(receiver,
265 holder,
266 cell,
267 name,
268 is_dont_delete);
269 if (!maybe_code->ToObject(&code)) return maybe_code;
270 }
271 PROFILE(isolate_,
272 CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
273 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
274 Object* result;
275 { MaybeObject* maybe_result =
276 receiver->UpdateMapCodeCache(name, Code::cast(code));
277 if (!maybe_result->ToObject(&result)) return maybe_result;
278 }
279 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100280 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000281}
282
283
Ben Murdoch85b71792012-04-11 18:30:58 +0100284MaybeObject* StubCache::ComputeKeyedLoadField(String* name,
285 JSObject* receiver,
286 JSObject* holder,
John Reck59135872010-11-02 12:39:01 -0700287 int field_index) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100288 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000289 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
Ben Murdoch85b71792012-04-11 18:30:58 +0100290 Object* code = receiver->map()->FindInCodeCache(name, flags);
291 if (code->IsUndefined()) {
292 KeyedLoadStubCompiler compiler;
293 { MaybeObject* maybe_code =
294 compiler.CompileLoadField(name, receiver, holder, field_index);
295 if (!maybe_code->ToObject(&code)) return maybe_code;
296 }
297 PROFILE(isolate_,
298 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
299 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
300 Object* result;
301 { MaybeObject* maybe_result =
302 receiver->UpdateMapCodeCache(name, Code::cast(code));
303 if (!maybe_result->ToObject(&result)) return maybe_result;
304 }
305 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000306 return code;
307}
308
309
Ben Murdoch85b71792012-04-11 18:30:58 +0100310MaybeObject* StubCache::ComputeKeyedLoadConstant(String* name,
311 JSObject* receiver,
312 JSObject* holder,
313 Object* value) {
314 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000315 Code::Flags flags =
316 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
Ben Murdoch85b71792012-04-11 18:30:58 +0100317 Object* code = receiver->map()->FindInCodeCache(name, flags);
318 if (code->IsUndefined()) {
319 KeyedLoadStubCompiler compiler;
320 { MaybeObject* maybe_code =
321 compiler.CompileLoadConstant(name, receiver, holder, value);
322 if (!maybe_code->ToObject(&code)) return maybe_code;
323 }
324 PROFILE(isolate_,
325 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
326 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
327 Object* result;
328 { MaybeObject* maybe_result =
329 receiver->UpdateMapCodeCache(name, Code::cast(code));
330 if (!maybe_result->ToObject(&result)) return maybe_result;
331 }
332 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000333 return code;
334}
335
336
Ben Murdoch85b71792012-04-11 18:30:58 +0100337MaybeObject* StubCache::ComputeKeyedLoadInterceptor(String* name,
338 JSObject* receiver,
339 JSObject* holder) {
340 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000341 Code::Flags flags =
342 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
Ben Murdoch85b71792012-04-11 18:30:58 +0100343 Object* code = receiver->map()->FindInCodeCache(name, flags);
344 if (code->IsUndefined()) {
345 KeyedLoadStubCompiler compiler;
346 { MaybeObject* maybe_code =
347 compiler.CompileLoadInterceptor(receiver, holder, name);
348 if (!maybe_code->ToObject(&code)) return maybe_code;
349 }
350 PROFILE(isolate_,
351 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
352 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
353 Object* result;
354 { MaybeObject* maybe_result =
355 receiver->UpdateMapCodeCache(name, Code::cast(code));
356 if (!maybe_result->ToObject(&result)) return maybe_result;
357 }
358 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000359 return code;
360}
361
362
Ben Murdoch85b71792012-04-11 18:30:58 +0100363MaybeObject* StubCache::ComputeKeyedLoadCallback(String* name,
364 JSObject* receiver,
365 JSObject* holder,
366 AccessorInfo* callback) {
367 ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
Steve Blocka7e24c12009-10-30 11:49:00 +0000368 Code::Flags flags =
369 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Ben Murdoch85b71792012-04-11 18:30:58 +0100370 Object* code = receiver->map()->FindInCodeCache(name, flags);
371 if (code->IsUndefined()) {
372 KeyedLoadStubCompiler compiler;
373 { MaybeObject* maybe_code =
374 compiler.CompileLoadCallback(name, receiver, holder, callback);
375 if (!maybe_code->ToObject(&code)) return maybe_code;
376 }
377 PROFILE(isolate_,
378 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
379 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
380 Object* result;
381 { MaybeObject* maybe_result =
382 receiver->UpdateMapCodeCache(name, Code::cast(code));
383 if (!maybe_result->ToObject(&result)) return maybe_result;
384 }
385 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000386 return code;
387}
388
389
Ben Murdoch85b71792012-04-11 18:30:58 +0100390
391MaybeObject* StubCache::ComputeKeyedLoadArrayLength(String* name,
392 JSArray* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000393 Code::Flags flags =
394 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Ben Murdoch85b71792012-04-11 18:30:58 +0100395 ASSERT(receiver->IsJSObject());
396 Object* code = receiver->map()->FindInCodeCache(name, flags);
397 if (code->IsUndefined()) {
398 KeyedLoadStubCompiler compiler;
399 { MaybeObject* maybe_code = compiler.CompileLoadArrayLength(name);
400 if (!maybe_code->ToObject(&code)) return maybe_code;
401 }
402 PROFILE(isolate_,
403 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
404 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
405 Object* result;
406 { MaybeObject* maybe_result =
407 receiver->UpdateMapCodeCache(name, Code::cast(code));
408 if (!maybe_result->ToObject(&result)) return maybe_result;
409 }
410 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000411 return code;
412}
413
414
Ben Murdoch85b71792012-04-11 18:30:58 +0100415MaybeObject* StubCache::ComputeKeyedLoadStringLength(String* name,
416 String* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000417 Code::Flags flags =
418 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Ben Murdoch85b71792012-04-11 18:30:58 +0100419 Map* map = receiver->map();
420 Object* code = map->FindInCodeCache(name, flags);
421 if (code->IsUndefined()) {
422 KeyedLoadStubCompiler compiler;
423 { MaybeObject* maybe_code = compiler.CompileLoadStringLength(name);
424 if (!maybe_code->ToObject(&code)) return maybe_code;
425 }
426 PROFILE(isolate_,
427 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
428 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
429 Object* result;
430 { MaybeObject* maybe_result = map->UpdateCodeCache(name, Code::cast(code));
431 if (!maybe_result->ToObject(&result)) return maybe_result;
432 }
433 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000434 return code;
435}
436
437
Ben Murdoch85b71792012-04-11 18:30:58 +0100438MaybeObject* StubCache::ComputeKeyedLoadFunctionPrototype(
439 String* name,
440 JSFunction* receiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000441 Code::Flags flags =
442 Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
Ben Murdoch85b71792012-04-11 18:30:58 +0100443 Object* code = receiver->map()->FindInCodeCache(name, flags);
444 if (code->IsUndefined()) {
445 KeyedLoadStubCompiler compiler;
446 { MaybeObject* maybe_code = compiler.CompileLoadFunctionPrototype(name);
447 if (!maybe_code->ToObject(&code)) return maybe_code;
448 }
449 PROFILE(isolate_,
450 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
451 GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
452 Object* result;
453 { MaybeObject* maybe_result =
454 receiver->UpdateMapCodeCache(name, Code::cast(code));
455 if (!maybe_result->ToObject(&result)) return maybe_result;
456 }
457 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000458 return code;
459}
460
461
Ben Murdoch85b71792012-04-11 18:30:58 +0100462MaybeObject* StubCache::ComputeStoreField(String* name,
463 JSObject* receiver,
John Reck59135872010-11-02 12:39:01 -0700464 int field_index,
Ben Murdoch85b71792012-04-11 18:30:58 +0100465 Map* transition,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100466 StrictModeFlag strict_mode) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100467 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
Steve Block1e0659c2011-05-24 12:43:12 +0100468 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100469 Code::STORE_IC, type, strict_mode);
Ben Murdoch85b71792012-04-11 18:30:58 +0100470 Object* code = receiver->map()->FindInCodeCache(name, flags);
471 if (code->IsUndefined()) {
472 StoreStubCompiler compiler(strict_mode);
473 { MaybeObject* maybe_code =
474 compiler.CompileStoreField(receiver, field_index, transition, name);
475 if (!maybe_code->ToObject(&code)) return maybe_code;
476 }
477 PROFILE(isolate_,
478 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
479 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
480 Object* result;
481 { MaybeObject* maybe_result =
482 receiver->UpdateMapCodeCache(name, Code::cast(code));
483 if (!maybe_result->ToObject(&result)) return maybe_result;
484 }
485 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100486 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000487}
488
489
Ben Murdoch85b71792012-04-11 18:30:58 +0100490MaybeObject* StubCache::ComputeKeyedLoadOrStoreElement(
491 JSObject* receiver,
492 bool is_store,
Ben Murdoch257744e2011-11-30 15:57:28 +0000493 StrictModeFlag strict_mode) {
494 Code::Flags flags =
495 Code::ComputeMonomorphicFlags(
Ben Murdoch85b71792012-04-11 18:30:58 +0100496 is_store ? Code::KEYED_STORE_IC :
497 Code::KEYED_LOAD_IC,
Ben Murdoch257744e2011-11-30 15:57:28 +0000498 NORMAL,
Ben Murdoch85b71792012-04-11 18:30:58 +0100499 strict_mode);
500 String* name = is_store
501 ? isolate()->heap()->KeyedStoreElementMonomorphic_symbol()
502 : isolate()->heap()->KeyedLoadElementMonomorphic_symbol();
503 Object* maybe_code = receiver->map()->FindInCodeCache(name, flags);
504 if (!maybe_code->IsUndefined()) return Code::cast(maybe_code);
Ben Murdoch257744e2011-11-30 15:57:28 +0000505
Ben Murdoch85b71792012-04-11 18:30:58 +0100506 MaybeObject* maybe_new_code = NULL;
507 Map* receiver_map = receiver->map();
508 if (is_store) {
509 KeyedStoreStubCompiler compiler(strict_mode);
510 maybe_new_code = compiler.CompileStoreElement(receiver_map);
Ben Murdoch257744e2011-11-30 15:57:28 +0000511 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +0100512 KeyedLoadStubCompiler compiler;
513 maybe_new_code = compiler.CompileLoadElement(receiver_map);
Ben Murdoch257744e2011-11-30 15:57:28 +0000514 }
Ben Murdoch85b71792012-04-11 18:30:58 +0100515 Code* code;
516 if (!maybe_new_code->To(&code)) return maybe_new_code;
517 if (is_store) {
518 PROFILE(isolate_,
519 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
520 Code::cast(code), 0));
521 } else {
522 PROFILE(isolate_,
523 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
524 Code::cast(code), 0));
525 }
526 ASSERT(code->IsCode());
527 Object* result;
528 { MaybeObject* maybe_result =
529 receiver->UpdateMapCodeCache(name, Code::cast(code));
530 if (!maybe_result->ToObject(&result)) return maybe_result;
531 }
Steve Block1e0659c2011-05-24 12:43:12 +0100532 return code;
533}
534
535
Ben Murdoch85b71792012-04-11 18:30:58 +0100536MaybeObject* StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
537 return isolate_->builtins()->builtin((strict_mode == kStrictMode)
538 ? Builtins::kStoreIC_Normal_Strict
539 : Builtins::kStoreIC_Normal);
Steve Block8defd9f2010-07-08 12:39:36 +0100540}
541
542
Ben Murdoch85b71792012-04-11 18:30:58 +0100543MaybeObject* StubCache::ComputeStoreGlobal(String* name,
544 GlobalObject* receiver,
545 JSGlobalPropertyCell* cell,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100546 StrictModeFlag strict_mode) {
Steve Block1e0659c2011-05-24 12:43:12 +0100547 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100548 Code::STORE_IC, NORMAL, strict_mode);
Ben Murdoch85b71792012-04-11 18:30:58 +0100549 Object* code = receiver->map()->FindInCodeCache(name, flags);
550 if (code->IsUndefined()) {
551 StoreStubCompiler compiler(strict_mode);
552 { MaybeObject* maybe_code =
553 compiler.CompileStoreGlobal(receiver, cell, name);
554 if (!maybe_code->ToObject(&code)) return maybe_code;
555 }
556 PROFILE(isolate_,
557 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
558 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
559 Object* result;
560 { MaybeObject* maybe_result =
561 receiver->UpdateMapCodeCache(name, Code::cast(code));
562 if (!maybe_result->ToObject(&result)) return maybe_result;
563 }
564 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100565 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000566}
567
568
Ben Murdoch85b71792012-04-11 18:30:58 +0100569MaybeObject* StubCache::ComputeStoreCallback(
570 String* name,
571 JSObject* receiver,
572 AccessorInfo* callback,
573 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000574 ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
Steve Block1e0659c2011-05-24 12:43:12 +0100575 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100576 Code::STORE_IC, CALLBACKS, strict_mode);
Ben Murdoch85b71792012-04-11 18:30:58 +0100577 Object* code = receiver->map()->FindInCodeCache(name, flags);
578 if (code->IsUndefined()) {
579 StoreStubCompiler compiler(strict_mode);
580 { MaybeObject* maybe_code =
581 compiler.CompileStoreCallback(receiver, callback, name);
582 if (!maybe_code->ToObject(&code)) return maybe_code;
583 }
584 PROFILE(isolate_,
585 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
586 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
587 Object* result;
588 { MaybeObject* maybe_result =
589 receiver->UpdateMapCodeCache(name, Code::cast(code));
590 if (!maybe_result->ToObject(&result)) return maybe_result;
591 }
592 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100593 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000594}
595
596
Ben Murdoch85b71792012-04-11 18:30:58 +0100597MaybeObject* StubCache::ComputeStoreInterceptor(
598 String* name,
599 JSObject* receiver,
600 StrictModeFlag strict_mode) {
Steve Block1e0659c2011-05-24 12:43:12 +0100601 Code::Flags flags = Code::ComputeMonomorphicFlags(
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100602 Code::STORE_IC, INTERCEPTOR, strict_mode);
Ben Murdoch85b71792012-04-11 18:30:58 +0100603 Object* code = receiver->map()->FindInCodeCache(name, flags);
604 if (code->IsUndefined()) {
605 StoreStubCompiler compiler(strict_mode);
606 { MaybeObject* maybe_code =
607 compiler.CompileStoreInterceptor(receiver, name);
608 if (!maybe_code->ToObject(&code)) return maybe_code;
609 }
610 PROFILE(isolate_,
611 CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
612 GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
613 Object* result;
614 { MaybeObject* maybe_result =
615 receiver->UpdateMapCodeCache(name, Code::cast(code));
616 if (!maybe_result->ToObject(&result)) return maybe_result;
617 }
618 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100619 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000620}
621
Ben Murdoch85b71792012-04-11 18:30:58 +0100622
623MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
624 JSObject* receiver,
John Reck59135872010-11-02 12:39:01 -0700625 int field_index,
Ben Murdoch85b71792012-04-11 18:30:58 +0100626 Map* transition,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100627 StrictModeFlag strict_mode) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100628 PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100629 Code::Flags flags = Code::ComputeMonomorphicFlags(
630 Code::KEYED_STORE_IC, type, strict_mode);
Ben Murdoch85b71792012-04-11 18:30:58 +0100631 Object* code = receiver->map()->FindInCodeCache(name, flags);
632 if (code->IsUndefined()) {
633 KeyedStoreStubCompiler compiler(strict_mode);
634 { MaybeObject* maybe_code =
635 compiler.CompileStoreField(receiver, field_index, transition, name);
636 if (!maybe_code->ToObject(&code)) return maybe_code;
637 }
638 PROFILE(isolate(),
639 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
640 Code::cast(code), name));
641 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, name, Code::cast(code)));
642 Object* result;
643 { MaybeObject* maybe_result =
644 receiver->UpdateMapCodeCache(name, Code::cast(code));
645 if (!maybe_result->ToObject(&result)) return maybe_result;
646 }
647 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000648 return code;
649}
650
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100651#define CALL_LOGGER_TAG(kind, type) \
652 (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
Steve Blocka7e24c12009-10-30 11:49:00 +0000653
Ben Murdoch85b71792012-04-11 18:30:58 +0100654MaybeObject* StubCache::ComputeCallConstant(int argc,
John Reck59135872010-11-02 12:39:01 -0700655 Code::Kind kind,
Ben Murdoch85b71792012-04-11 18:30:58 +0100656 Code::ExtraICState extra_ic_state,
657 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 =
Ben Murdoch85b71792012-04-11 18:30:58 +0100663 IC::GetCodeCacheForObject(object, holder);
664 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 Murdoch85b71792012-04-11 18:30:58 +0100676 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
677 CONSTANT_FUNCTION,
678 extra_ic_state,
679 cache_holder,
680 argc);
681 Object* code = map_holder->map()->FindInCodeCache(name, flags);
682 if (code->IsUndefined()) {
683 // If the function hasn't been compiled yet, we cannot do it now
684 // because it may cause GC. To avoid this issue, we return an
685 // internal error which will make sure we do not update any
686 // caches.
687 if (!function->is_compiled()) return Failure::InternalError();
688 // Compile the stub - only create stubs for fully compiled functions.
689 CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
690 { MaybeObject* maybe_code =
691 compiler.CompileCallConstant(object, holder, function, name, check);
692 if (!maybe_code->ToObject(&code)) return maybe_code;
693 }
694 Code::cast(code)->set_check_type(check);
695 ASSERT_EQ(flags, Code::cast(code)->flags());
696 PROFILE(isolate_,
697 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
698 Code::cast(code), name));
699 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
700 Object* result;
701 { MaybeObject* maybe_result =
702 map_holder->UpdateMapCodeCache(name, Code::cast(code));
703 if (!maybe_result->ToObject(&result)) return maybe_result;
704 }
705 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100706 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000707}
708
709
Ben Murdoch85b71792012-04-11 18:30:58 +0100710MaybeObject* StubCache::ComputeCallField(int argc,
John Reck59135872010-11-02 12:39:01 -0700711 Code::Kind kind,
Ben Murdoch85b71792012-04-11 18:30:58 +0100712 Code::ExtraICState extra_ic_state,
713 String* name,
714 Object* object,
715 JSObject* holder,
John Reck59135872010-11-02 12:39:01 -0700716 int index) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000717 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100718 InlineCacheHolderFlag cache_holder =
Ben Murdoch85b71792012-04-11 18:30:58 +0100719 IC::GetCodeCacheForObject(object, holder);
720 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000721
722 // TODO(1233596): We cannot do receiver map check for non-JS objects
723 // because they may be represented as immediates without a
724 // map. Instead, we check against the map in the holder.
725 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
726 object = holder;
727 }
728
Ben Murdoch85b71792012-04-11 18:30:58 +0100729 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
730 FIELD,
731 extra_ic_state,
732 cache_holder,
733 argc);
734 Object* code = map_holder->map()->FindInCodeCache(name, flags);
735 if (code->IsUndefined()) {
736 CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
737 { MaybeObject* maybe_code =
738 compiler.CompileCallField(JSObject::cast(object),
739 holder,
740 index,
741 name);
742 if (!maybe_code->ToObject(&code)) return maybe_code;
743 }
744 ASSERT_EQ(flags, Code::cast(code)->flags());
745 PROFILE(isolate_,
746 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
747 Code::cast(code), name));
748 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
749 Object* result;
750 { MaybeObject* maybe_result =
751 map_holder->UpdateMapCodeCache(name, Code::cast(code));
752 if (!maybe_result->ToObject(&result)) return maybe_result;
753 }
754 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100755 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000756}
757
758
Ben Murdoch85b71792012-04-11 18:30:58 +0100759MaybeObject* StubCache::ComputeCallInterceptor(
760 int argc,
761 Code::Kind kind,
762 Code::ExtraICState extra_ic_state,
763 String* name,
764 Object* object,
765 JSObject* holder) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000766 // Compute the check type and the map.
Steve Block8defd9f2010-07-08 12:39:36 +0100767 InlineCacheHolderFlag cache_holder =
Ben Murdoch85b71792012-04-11 18:30:58 +0100768 IC::GetCodeCacheForObject(object, holder);
769 JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000770
771 // TODO(1233596): We cannot do receiver map check for non-JS objects
772 // because they may be represented as immediates without a
773 // map. Instead, we check against the map in the holder.
774 if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
775 object = holder;
776 }
777
Ben Murdoch85b71792012-04-11 18:30:58 +0100778 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
779 INTERCEPTOR,
780 extra_ic_state,
781 cache_holder,
782 argc);
783 Object* code = map_holder->map()->FindInCodeCache(name, flags);
784 if (code->IsUndefined()) {
785 CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
786 { MaybeObject* maybe_code =
787 compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
788 if (!maybe_code->ToObject(&code)) return maybe_code;
789 }
790 ASSERT_EQ(flags, Code::cast(code)->flags());
791 PROFILE(isolate(),
792 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
793 Code::cast(code), name));
794 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
795 Object* result;
796 { MaybeObject* maybe_result =
797 map_holder->UpdateMapCodeCache(name, Code::cast(code));
798 if (!maybe_result->ToObject(&result)) return maybe_result;
799 }
800 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100801 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000802}
803
804
Ben Murdoch85b71792012-04-11 18:30:58 +0100805MaybeObject* StubCache::ComputeCallNormal(int argc,
John Reck59135872010-11-02 12:39:01 -0700806 Code::Kind kind,
Ben Murdoch85b71792012-04-11 18:30:58 +0100807 Code::ExtraICState extra_ic_state,
808 String* name,
809 JSObject* receiver) {
810 Object* code;
811 { MaybeObject* maybe_code = ComputeCallNormal(argc, kind, extra_ic_state);
812 if (!maybe_code->ToObject(&code)) return maybe_code;
813 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100814 return code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000815}
816
817
Ben Murdoch85b71792012-04-11 18:30:58 +0100818MaybeObject* StubCache::ComputeCallGlobal(int argc,
819 Code::Kind kind,
820 Code::ExtraICState extra_ic_state,
821 String* name,
822 JSObject* receiver,
823 GlobalObject* holder,
824 JSGlobalPropertyCell* cell,
825 JSFunction* function) {
826 InlineCacheHolderFlag cache_holder =
827 IC::GetCodeCacheForObject(receiver, holder);
828 JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder);
829 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
830 NORMAL,
831 extra_ic_state,
832 cache_holder,
833 argc);
834 Object* code = map_holder->map()->FindInCodeCache(name, flags);
835 if (code->IsUndefined()) {
836 // If the function hasn't been compiled yet, we cannot do it now
837 // because it may cause GC. To avoid this issue, we return an
838 // internal error which will make sure we do not update any
839 // caches.
840 if (!function->is_compiled()) return Failure::InternalError();
841 CallStubCompiler compiler(argc, kind, extra_ic_state, cache_holder);
842 { MaybeObject* maybe_code =
843 compiler.CompileCallGlobal(receiver, holder, cell, function, name);
844 if (!maybe_code->ToObject(&code)) return maybe_code;
845 }
846 ASSERT_EQ(flags, Code::cast(code)->flags());
847 PROFILE(isolate(),
848 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
849 Code::cast(code), name));
850 GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
851 Object* result;
852 { MaybeObject* maybe_result =
853 map_holder->UpdateMapCodeCache(name, Code::cast(code));
854 if (!maybe_result->ToObject(&result)) return maybe_result;
855 }
856 }
857 return code;
858}
859
860
861static Object* GetProbeValue(Isolate* isolate, Code::Flags flags) {
862 // Use raw_unchecked... so we don't get assert failures during GC.
863 UnseededNumberDictionary* dictionary =
864 isolate->heap()->raw_unchecked_non_monomorphic_cache();
865 int entry = dictionary->FindEntry(isolate, flags);
866 if (entry != -1) return dictionary->ValueAt(entry);
867 return isolate->heap()->raw_unchecked_undefined_value();
868}
869
870
871MUST_USE_RESULT static MaybeObject* ProbeCache(Isolate* isolate,
872 Code::Flags flags) {
873 Heap* heap = isolate->heap();
874 Object* probe = GetProbeValue(isolate, flags);
875 if (probe != heap->undefined_value()) return probe;
876 // Seed the cache with an undefined value to make sure that any
877 // generated code object can always be inserted into the cache
878 // without causing allocation failures.
879 Object* result;
880 { MaybeObject* maybe_result =
881 heap->non_monomorphic_cache()->AtNumberPut(flags,
882 heap->undefined_value());
883 if (!maybe_result->ToObject(&result)) return maybe_result;
884 }
885 heap->public_set_non_monomorphic_cache(
886 UnseededNumberDictionary::cast(result));
887 return probe;
888}
889
890
891static MaybeObject* FillCache(Isolate* isolate, MaybeObject* maybe_code) {
892 Object* code;
893 if (maybe_code->ToObject(&code)) {
894 if (code->IsCode()) {
895 Heap* heap = isolate->heap();
896 int entry = heap->non_monomorphic_cache()->FindEntry(
897 Code::cast(code)->flags());
898 // The entry must be present see comment in ProbeCache.
899 ASSERT(entry != -1);
900 ASSERT(heap->non_monomorphic_cache()->ValueAt(entry) ==
901 heap->undefined_value());
902 heap->non_monomorphic_cache()->ValueAtPut(entry, code);
903 CHECK(GetProbeValue(isolate, Code::cast(code)->flags()) == code);
904 }
905 }
906 return maybe_code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000907}
908
909
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100910Code* StubCache::FindCallInitialize(int argc,
Ben Murdoch257744e2011-11-30 15:57:28 +0000911 RelocInfo::Mode mode,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100912 Code::Kind kind) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000913 Code::ExtraICState extra_state =
914 CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
915 CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
Ben Murdoch85b71792012-04-11 18:30:58 +0100916 Code::Flags flags = Code::ComputeFlags(kind,
917 UNINITIALIZED,
918 extra_state,
919 NORMAL,
920 argc);
921 Object* result = ProbeCache(isolate(), flags)->ToObjectUnchecked();
922 ASSERT(result != heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000923 // This might be called during the marking phase of the collector
924 // hence the unchecked cast.
Ben Murdoch85b71792012-04-11 18:30:58 +0100925 return reinterpret_cast<Code*>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000926}
927
928
Ben Murdoch85b71792012-04-11 18:30:58 +0100929MaybeObject* StubCache::ComputeCallInitialize(int argc,
Ben Murdoch257744e2011-11-30 15:57:28 +0000930 RelocInfo::Mode mode,
John Reck59135872010-11-02 12:39:01 -0700931 Code::Kind kind) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000932 Code::ExtraICState extra_state =
933 CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
934 CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
Ben Murdoch85b71792012-04-11 18:30:58 +0100935 Code::Flags flags = Code::ComputeFlags(kind,
936 UNINITIALIZED,
937 extra_state,
938 NORMAL,
939 argc);
940 Object* probe;
941 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
942 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
943 }
944 if (!probe->IsUndefined()) return probe;
945 StubCompiler compiler;
946 return FillCache(isolate_, compiler.CompileCallInitialize(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +0000947}
948
949
Ben Murdoch85b71792012-04-11 18:30:58 +0100950Handle<Code> StubCache::ComputeCallInitialize(int argc,
951 RelocInfo::Mode mode) {
952 CALL_HEAP_FUNCTION(isolate_,
953 ComputeCallInitialize(argc, mode, Code::CALL_IC),
954 Code);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800955}
956
957
Ben Murdoch589d6972011-11-30 16:04:58 +0000958Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100959 CALL_HEAP_FUNCTION(
960 isolate_,
961 ComputeCallInitialize(argc, RelocInfo::CODE_TARGET, Code::KEYED_CALL_IC),
962 Code);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800963}
964
965
Ben Murdoch85b71792012-04-11 18:30:58 +0100966MaybeObject* StubCache::ComputeCallPreMonomorphic(
Ben Murdoch257744e2011-11-30 15:57:28 +0000967 int argc,
Ben Murdoch257744e2011-11-30 15:57:28 +0000968 Code::Kind kind,
Ben Murdoch85b71792012-04-11 18:30:58 +0100969 Code::ExtraICState extra_ic_state) {
970 Code::Flags flags = Code::ComputeFlags(kind,
971 PREMONOMORPHIC,
972 extra_ic_state,
973 NORMAL,
974 argc);
975 Object* probe;
976 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
977 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
978 }
979 if (!probe->IsUndefined()) return probe;
980 StubCompiler compiler;
981 return FillCache(isolate_, compiler.CompileCallPreMonomorphic(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +0000982}
983
984
Ben Murdoch85b71792012-04-11 18:30:58 +0100985MaybeObject* StubCache::ComputeCallNormal(int argc,
Ben Murdoch257744e2011-11-30 15:57:28 +0000986 Code::Kind kind,
Ben Murdoch85b71792012-04-11 18:30:58 +0100987 Code::ExtraICState extra_ic_state) {
988 Code::Flags flags = Code::ComputeFlags(kind,
989 MONOMORPHIC,
990 extra_ic_state,
991 NORMAL,
992 argc);
993 Object* probe;
994 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
995 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
996 }
997 if (!probe->IsUndefined()) return probe;
998 StubCompiler compiler;
999 return FillCache(isolate_, compiler.CompileCallNormal(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001000}
1001
1002
Ben Murdoch85b71792012-04-11 18:30:58 +01001003MaybeObject* StubCache::ComputeCallArguments(int argc, Code::Kind kind) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001004 ASSERT(kind == Code::KEYED_CALL_IC);
Ben Murdoch85b71792012-04-11 18:30:58 +01001005 Code::Flags flags = Code::ComputeFlags(kind,
1006 MEGAMORPHIC,
1007 Code::kNoExtraICState,
1008 NORMAL,
1009 argc);
1010 Object* probe;
1011 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1012 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1013 }
1014 if (!probe->IsUndefined()) return probe;
1015 StubCompiler compiler;
1016 return FillCache(isolate_, compiler.CompileCallArguments(flags));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001017}
1018
1019
Ben Murdoch85b71792012-04-11 18:30:58 +01001020MaybeObject* StubCache::ComputeCallMegamorphic(
Ben Murdoch257744e2011-11-30 15:57:28 +00001021 int argc,
Ben Murdoch257744e2011-11-30 15:57:28 +00001022 Code::Kind kind,
Ben Murdoch85b71792012-04-11 18:30:58 +01001023 Code::ExtraICState extra_ic_state) {
1024 Code::Flags flags = Code::ComputeFlags(kind,
1025 MEGAMORPHIC,
1026 extra_ic_state,
1027 NORMAL,
1028 argc);
1029 Object* probe;
1030 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1031 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1032 }
1033 if (!probe->IsUndefined()) return probe;
1034 StubCompiler compiler;
1035 return FillCache(isolate_, compiler.CompileCallMegamorphic(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001036}
1037
1038
Ben Murdoch85b71792012-04-11 18:30:58 +01001039MaybeObject* StubCache::ComputeCallMiss(int argc,
Ben Murdoch257744e2011-11-30 15:57:28 +00001040 Code::Kind kind,
Ben Murdoch85b71792012-04-11 18:30:58 +01001041 Code::ExtraICState extra_ic_state) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001042 // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
1043 // and monomorphic stubs are not mixed up together in the stub cache.
Ben Murdoch85b71792012-04-11 18:30:58 +01001044 Code::Flags flags = Code::ComputeFlags(kind,
1045 MONOMORPHIC_PROTOTYPE_FAILURE,
1046 extra_ic_state,
1047 NORMAL,
1048 argc,
1049 OWN_MAP);
1050 Object* probe;
1051 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1052 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1053 }
1054 if (!probe->IsUndefined()) return probe;
1055 StubCompiler compiler;
1056 return FillCache(isolate_, compiler.CompileCallMiss(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001057}
1058
1059
1060#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdoch85b71792012-04-11 18:30:58 +01001061MaybeObject* StubCache::ComputeCallDebugBreak(
1062 int argc,
1063 Code::Kind kind) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001064 // Extra IC state is irrelevant for debug break ICs. They jump to
1065 // the actual call ic to carry out the work.
Ben Murdoch85b71792012-04-11 18:30:58 +01001066 Code::Flags flags = Code::ComputeFlags(kind,
1067 DEBUG_BREAK,
1068 Code::kNoExtraICState,
1069 NORMAL,
1070 argc);
1071 Object* probe;
1072 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1073 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1074 }
1075 if (!probe->IsUndefined()) return probe;
1076 StubCompiler compiler;
1077 return FillCache(isolate_, compiler.CompileCallDebugBreak(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001078}
1079
1080
Ben Murdoch85b71792012-04-11 18:30:58 +01001081MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(
1082 int argc,
1083 Code::Kind kind) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001084 // Extra IC state is irrelevant for debug break ICs. They jump to
1085 // the actual call ic to carry out the work.
Ben Murdoch85b71792012-04-11 18:30:58 +01001086 Code::Flags flags = Code::ComputeFlags(kind,
1087 DEBUG_PREPARE_STEP_IN,
1088 Code::kNoExtraICState,
1089 NORMAL,
1090 argc);
1091 Object* probe;
1092 { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1093 if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1094 }
1095 if (!probe->IsUndefined()) return probe;
1096 StubCompiler compiler;
1097 return FillCache(isolate_, compiler.CompileCallDebugPrepareStepIn(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +00001098}
1099#endif
1100
1101
Steve Blocka7e24c12009-10-30 11:49:00 +00001102void StubCache::Clear() {
1103 for (int i = 0; i < kPrimaryTableSize; i++) {
Steve Block44f0eee2011-05-26 01:26:41 +01001104 primary_[i].key = heap()->empty_string();
Ben Murdoch85b71792012-04-11 18:30:58 +01001105 primary_[i].value = isolate_->builtins()->builtin(
1106 Builtins::kIllegal);
Steve Blocka7e24c12009-10-30 11:49:00 +00001107 }
1108 for (int j = 0; j < kSecondaryTableSize; j++) {
Steve Block44f0eee2011-05-26 01:26:41 +01001109 secondary_[j].key = heap()->empty_string();
Ben Murdoch85b71792012-04-11 18:30:58 +01001110 secondary_[j].value = isolate_->builtins()->builtin(
1111 Builtins::kIllegal);
Steve Blocka7e24c12009-10-30 11:49:00 +00001112 }
1113}
1114
1115
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001116void StubCache::CollectMatchingMaps(SmallMapList* types,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001117 String* name,
Ben Murdoch85b71792012-04-11 18:30:58 +01001118 Code::Flags flags) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001119 for (int i = 0; i < kPrimaryTableSize; i++) {
1120 if (primary_[i].key == name) {
1121 Map* map = primary_[i].value->FindFirstMap();
1122 // Map can be NULL, if the stub is constant function call
1123 // with a primitive receiver.
1124 if (map == NULL) continue;
1125
1126 int offset = PrimaryOffset(name, flags, map);
Ben Murdoch85b71792012-04-11 18:30:58 +01001127 if (entry(primary_, offset) == &primary_[i]) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001128 types->Add(Handle<Map>(map));
1129 }
1130 }
1131 }
1132
1133 for (int i = 0; i < kSecondaryTableSize; i++) {
1134 if (secondary_[i].key == name) {
1135 Map* map = secondary_[i].value->FindFirstMap();
1136 // Map can be NULL, if the stub is constant function call
1137 // with a primitive receiver.
1138 if (map == NULL) continue;
1139
1140 // Lookup in primary table and skip duplicates.
1141 int primary_offset = PrimaryOffset(name, flags, map);
1142 Entry* primary_entry = entry(primary_, primary_offset);
1143 if (primary_entry->key == name) {
1144 Map* primary_map = primary_entry->value->FindFirstMap();
1145 if (map == primary_map) continue;
1146 }
1147
1148 // Lookup in secondary table and add matches.
1149 int offset = SecondaryOffset(name, flags, primary_offset);
Ben Murdoch85b71792012-04-11 18:30:58 +01001150 if (entry(secondary_, offset) == &secondary_[i]) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001151 types->Add(Handle<Map>(map));
1152 }
1153 }
1154 }
1155}
1156
1157
Steve Blocka7e24c12009-10-30 11:49:00 +00001158// ------------------------------------------------------------------------
1159// StubCompiler implementation.
1160
1161
Ben Murdoch8b112d22011-06-08 16:22:53 +01001162RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) {
Steve Blockd0582a62009-12-15 09:54:21 +00001163 ASSERT(args[0]->IsJSObject());
1164 ASSERT(args[1]->IsJSObject());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001165 AccessorInfo* callback = AccessorInfo::cast(args[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001166 Address getter_address = v8::ToCData<Address>(callback->getter());
1167 v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
1168 ASSERT(fun != NULL);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001169 v8::AccessorInfo info(&args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01001170 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001171 v8::Handle<v8::Value> result;
1172 {
1173 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001174 VMState state(isolate, EXTERNAL);
1175 ExternalCallbackScope call_scope(isolate, getter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001176 result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
1177 }
Steve Block44f0eee2011-05-26 01:26:41 +01001178 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1179 if (result.IsEmpty()) return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001180 return *v8::Utils::OpenHandle(*result);
1181}
1182
1183
Ben Murdoch8b112d22011-06-08 16:22:53 +01001184RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001185 JSObject* recv = JSObject::cast(args[0]);
1186 AccessorInfo* callback = AccessorInfo::cast(args[1]);
1187 Address setter_address = v8::ToCData<Address>(callback->setter());
1188 v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
1189 ASSERT(fun != NULL);
1190 Handle<String> name = args.at<String>(2);
1191 Handle<Object> value = args.at<Object>(3);
Steve Block44f0eee2011-05-26 01:26:41 +01001192 HandleScope scope(isolate);
1193 LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
1194 CustomArguments custom_args(isolate, callback->data(), recv, recv);
Steve Blocka7e24c12009-10-30 11:49:00 +00001195 v8::AccessorInfo info(custom_args.end());
1196 {
1197 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001198 VMState state(isolate, EXTERNAL);
1199 ExternalCallbackScope call_scope(isolate, setter_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001200 fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
1201 }
Steve Block44f0eee2011-05-26 01:26:41 +01001202 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001203 return *value;
1204}
1205
Steve Block6ded16b2010-05-10 14:33:55 +01001206
1207static const int kAccessorInfoOffsetInInterceptorArgs = 2;
1208
1209
Steve Blocka7e24c12009-10-30 11:49:00 +00001210/**
1211 * Attempts to load a property with an interceptor (which must be present),
1212 * but doesn't search the prototype chain.
1213 *
1214 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
1215 * provide any value for the given name.
1216 */
Ben Murdoch8b112d22011-06-08 16:22:53 +01001217RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
Steve Block6ded16b2010-05-10 14:33:55 +01001218 Handle<String> name_handle = args.at<String>(0);
1219 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
1220 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1221 ASSERT(args[2]->IsJSObject()); // Receiver.
1222 ASSERT(args[3]->IsJSObject()); // Holder.
1223 ASSERT(args.length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001224
1225 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1226 v8::NamedPropertyGetter getter =
1227 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1228 ASSERT(getter != NULL);
1229
1230 {
1231 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001232 v8::AccessorInfo info(args.arguments() -
1233 kAccessorInfoOffsetInInterceptorArgs);
Steve Block44f0eee2011-05-26 01:26:41 +01001234 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001235 v8::Handle<v8::Value> r;
1236 {
1237 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001238 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001239 r = getter(v8::Utils::ToLocal(name_handle), info);
1240 }
Steve Block44f0eee2011-05-26 01:26:41 +01001241 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001242 if (!r.IsEmpty()) {
1243 return *v8::Utils::OpenHandle(*r);
1244 }
1245 }
1246
Steve Block44f0eee2011-05-26 01:26:41 +01001247 return isolate->heap()->no_interceptor_result_sentinel();
Steve Blocka7e24c12009-10-30 11:49:00 +00001248}
1249
1250
John Reck59135872010-11-02 12:39:01 -07001251static MaybeObject* ThrowReferenceError(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001252 // If the load is non-contextual, just return the undefined result.
1253 // Note that both keyed and non-keyed loads may end up here, so we
1254 // can't use either LoadIC or KeyedLoadIC constructors.
Steve Block44f0eee2011-05-26 01:26:41 +01001255 IC ic(IC::NO_EXTRA_FRAME, Isolate::Current());
Steve Blocka7e24c12009-10-30 11:49:00 +00001256 ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01001257 if (!ic.SlowIsContextual()) return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001258
1259 // Throw a reference error.
1260 HandleScope scope;
1261 Handle<String> name_handle(name);
1262 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01001263 FACTORY->NewReferenceError("not_defined",
Steve Blocka7e24c12009-10-30 11:49:00 +00001264 HandleVector(&name_handle, 1));
Steve Block44f0eee2011-05-26 01:26:41 +01001265 return Isolate::Current()->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00001266}
1267
1268
John Reck59135872010-11-02 12:39:01 -07001269static MaybeObject* LoadWithInterceptor(Arguments* args,
1270 PropertyAttributes* attrs) {
Steve Block6ded16b2010-05-10 14:33:55 +01001271 Handle<String> name_handle = args->at<String>(0);
1272 Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
1273 ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1274 Handle<JSObject> receiver_handle = args->at<JSObject>(2);
1275 Handle<JSObject> holder_handle = args->at<JSObject>(3);
1276 ASSERT(args->length() == 5); // Last arg is data object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001277
Steve Block44f0eee2011-05-26 01:26:41 +01001278 Isolate* isolate = receiver_handle->GetIsolate();
1279
Steve Blocka7e24c12009-10-30 11:49:00 +00001280 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1281 v8::NamedPropertyGetter getter =
1282 FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1283 ASSERT(getter != NULL);
1284
1285 {
1286 // Use the interceptor getter.
Steve Block6ded16b2010-05-10 14:33:55 +01001287 v8::AccessorInfo info(args->arguments() -
1288 kAccessorInfoOffsetInInterceptorArgs);
Steve Block44f0eee2011-05-26 01:26:41 +01001289 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001290 v8::Handle<v8::Value> r;
1291 {
1292 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001293 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001294 r = getter(v8::Utils::ToLocal(name_handle), info);
1295 }
Steve Block44f0eee2011-05-26 01:26:41 +01001296 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001297 if (!r.IsEmpty()) {
1298 *attrs = NONE;
1299 return *v8::Utils::OpenHandle(*r);
1300 }
1301 }
1302
John Reck59135872010-11-02 12:39:01 -07001303 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00001304 *receiver_handle,
1305 *name_handle,
1306 attrs);
Steve Block44f0eee2011-05-26 01:26:41 +01001307 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001308 return result;
1309}
1310
1311
1312/**
1313 * Loads a property with an interceptor performing post interceptor
1314 * lookup if interceptor failed.
1315 */
Ben Murdoch8b112d22011-06-08 16:22:53 +01001316RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001317 PropertyAttributes attr = NONE;
John Reck59135872010-11-02 12:39:01 -07001318 Object* result;
1319 { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
1320 if (!maybe_result->ToObject(&result)) return maybe_result;
1321 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001322
1323 // If the property is present, return it.
1324 if (attr != ABSENT) return result;
Steve Block6ded16b2010-05-10 14:33:55 +01001325 return ThrowReferenceError(String::cast(args[0]));
Steve Blocka7e24c12009-10-30 11:49:00 +00001326}
1327
1328
Ben Murdoch8b112d22011-06-08 16:22:53 +01001329RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001330 PropertyAttributes attr;
John Reck59135872010-11-02 12:39:01 -07001331 MaybeObject* result = LoadWithInterceptor(&args, &attr);
Steve Block44f0eee2011-05-26 01:26:41 +01001332 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001333 // This is call IC. In this case, we simply return the undefined result which
1334 // will lead to an exception when trying to invoke the result as a
1335 // function.
1336 return result;
1337}
1338
1339
Ben Murdoch8b112d22011-06-08 16:22:53 +01001340RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001341 ASSERT(args.length() == 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001342 JSObject* recv = JSObject::cast(args[0]);
1343 String* name = String::cast(args[1]);
1344 Object* value = args[2];
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001345 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
Ben Murdoch85b71792012-04-11 18:30:58 +01001346 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001347 ASSERT(recv->HasNamedInterceptor());
1348 PropertyAttributes attr = NONE;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001349 MaybeObject* result = recv->SetPropertyWithInterceptor(
1350 name, value, attr, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001351 return result;
1352}
1353
1354
Ben Murdoch8b112d22011-06-08 16:22:53 +01001355RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001356 JSObject* receiver = JSObject::cast(args[0]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001357 ASSERT(args.smi_at(1) >= 0);
1358 uint32_t index = args.smi_at(1);
Andrei Popescu402d9372010-02-26 13:31:12 +00001359 return receiver->GetElementWithInterceptor(receiver, index);
1360}
1361
1362
Ben Murdoch85b71792012-04-11 18:30:58 +01001363MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
1364 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001365 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001366 Code::Kind kind = Code::ExtractKindFromFlags(flags);
Ben Murdoch85b71792012-04-11 18:30:58 +01001367 Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001368 if (kind == Code::CALL_IC) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001369 CallIC::GenerateInitialize(masm(), argc, extra_ic_state);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001370 } else {
1371 KeyedCallIC::GenerateInitialize(masm(), argc);
1372 }
Ben Murdoch85b71792012-04-11 18:30:58 +01001373 Object* result;
1374 { MaybeObject* maybe_result =
1375 GetCodeWithFlags(flags, "CompileCallInitialize");
1376 if (!maybe_result->ToObject(&result)) return maybe_result;
1377 }
Steve Block44f0eee2011-05-26 01:26:41 +01001378 isolate()->counters()->call_initialize_stubs()->Increment();
Ben Murdoch85b71792012-04-11 18:30:58 +01001379 Code* code = Code::cast(result);
1380 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001381 PROFILE(isolate(),
1382 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
Ben Murdoch85b71792012-04-11 18:30:58 +01001383 code, code->arguments_count()));
1384 GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, Code::cast(code)));
1385 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001386}
1387
1388
Ben Murdoch85b71792012-04-11 18:30:58 +01001389MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
1390 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001391 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1392 // The code of the PreMonomorphic stub is the same as the code
1393 // of the Initialized stub. They just differ on the code object flags.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001394 Code::Kind kind = Code::ExtractKindFromFlags(flags);
Ben Murdoch85b71792012-04-11 18:30:58 +01001395 Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001396 if (kind == Code::CALL_IC) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001397 CallIC::GenerateInitialize(masm(), argc, extra_ic_state);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001398 } else {
1399 KeyedCallIC::GenerateInitialize(masm(), argc);
1400 }
Ben Murdoch85b71792012-04-11 18:30:58 +01001401 Object* result;
1402 { MaybeObject* maybe_result =
1403 GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1404 if (!maybe_result->ToObject(&result)) return maybe_result;
1405 }
Steve Block44f0eee2011-05-26 01:26:41 +01001406 isolate()->counters()->call_premonomorphic_stubs()->Increment();
Ben Murdoch85b71792012-04-11 18:30:58 +01001407 Code* code = Code::cast(result);
1408 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001409 PROFILE(isolate(),
1410 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
Ben Murdoch85b71792012-04-11 18:30:58 +01001411 code, code->arguments_count()));
1412 GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, Code::cast(code)));
1413 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001414}
1415
1416
Ben Murdoch85b71792012-04-11 18:30:58 +01001417MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
1418 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001419 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001420 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1421 if (kind == Code::CALL_IC) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001422 // Call normal is always with a explict receiver.
1423 ASSERT(!CallIC::Contextual::decode(
1424 Code::ExtractExtraICStateFromFlags(flags)));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001425 CallIC::GenerateNormal(masm(), argc);
1426 } else {
1427 KeyedCallIC::GenerateNormal(masm(), argc);
1428 }
Ben Murdoch85b71792012-04-11 18:30:58 +01001429 Object* result;
1430 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallNormal");
1431 if (!maybe_result->ToObject(&result)) return maybe_result;
1432 }
Steve Block44f0eee2011-05-26 01:26:41 +01001433 isolate()->counters()->call_normal_stubs()->Increment();
Ben Murdoch85b71792012-04-11 18:30:58 +01001434 Code* code = Code::cast(result);
1435 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001436 PROFILE(isolate(),
1437 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
Ben Murdoch85b71792012-04-11 18:30:58 +01001438 code, code->arguments_count()));
1439 GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, Code::cast(code)));
1440 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001441}
1442
1443
Ben Murdoch85b71792012-04-11 18:30:58 +01001444MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
1445 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001446 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001447 Code::Kind kind = Code::ExtractKindFromFlags(flags);
Ben Murdoch85b71792012-04-11 18:30:58 +01001448 Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001449 if (kind == Code::CALL_IC) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001450 CallIC::GenerateMegamorphic(masm(), argc, extra_ic_state);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001451 } else {
1452 KeyedCallIC::GenerateMegamorphic(masm(), argc);
1453 }
Ben Murdoch85b71792012-04-11 18:30:58 +01001454 Object* result;
1455 { MaybeObject* maybe_result =
1456 GetCodeWithFlags(flags, "CompileCallMegamorphic");
1457 if (!maybe_result->ToObject(&result)) return maybe_result;
1458 }
Steve Block44f0eee2011-05-26 01:26:41 +01001459 isolate()->counters()->call_megamorphic_stubs()->Increment();
Ben Murdoch85b71792012-04-11 18:30:58 +01001460 Code* code = Code::cast(result);
1461 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001462 PROFILE(isolate(),
1463 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
Ben Murdoch85b71792012-04-11 18:30:58 +01001464 code, code->arguments_count()));
1465 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
1466 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001467}
1468
1469
Ben Murdoch85b71792012-04-11 18:30:58 +01001470MaybeObject* StubCompiler::CompileCallArguments(Code::Flags flags) {
1471 HandleScope scope(isolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001472 int argc = Code::ExtractArgumentsCountFromFlags(flags);
1473 KeyedCallIC::GenerateNonStrictArguments(masm(), argc);
Ben Murdoch85b71792012-04-11 18:30:58 +01001474 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1475 Object* result;
1476 { MaybeObject* maybe_result =
1477 GetCodeWithFlags(flags, "CompileCallArguments");
1478 if (!maybe_result->ToObject(&result)) return maybe_result;
1479 }
1480 Code* code = Code::cast(result);
1481 USE(code);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001482 PROFILE(isolate(),
Ben Murdoch85b71792012-04-11 18:30:58 +01001483 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
1484 code, code->arguments_count()));
1485 GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
1486 return result;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001487}
1488
1489
Ben Murdoch85b71792012-04-11 18:30:58 +01001490MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
1491 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001492 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001493 Code::Kind kind = Code::ExtractKindFromFlags(flags);
Ben Murdoch85b71792012-04-11 18:30:58 +01001494 Code::ExtraICState extra_ic_state = Code::ExtractExtraICStateFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001495 if (kind == Code::CALL_IC) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001496 CallIC::GenerateMiss(masm(), argc, extra_ic_state);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001497 } else {
1498 KeyedCallIC::GenerateMiss(masm(), argc);
1499 }
Ben Murdoch85b71792012-04-11 18:30:58 +01001500 Object* result;
1501 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallMiss");
1502 if (!maybe_result->ToObject(&result)) return maybe_result;
1503 }
Steve Block44f0eee2011-05-26 01:26:41 +01001504 isolate()->counters()->call_megamorphic_stubs()->Increment();
Ben Murdoch85b71792012-04-11 18:30:58 +01001505 Code* code = Code::cast(result);
1506 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001507 PROFILE(isolate(),
1508 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
Ben Murdoch85b71792012-04-11 18:30:58 +01001509 code, code->arguments_count()));
1510 GDBJIT(AddCode(GDBJITInterface::CALL_MISS, Code::cast(code)));
1511 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001512}
1513
1514
1515#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdoch85b71792012-04-11 18:30:58 +01001516MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
1517 HandleScope scope(isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001518 Debug::GenerateCallICDebugBreak(masm());
Ben Murdoch85b71792012-04-11 18:30:58 +01001519 Object* result;
1520 { MaybeObject* maybe_result =
1521 GetCodeWithFlags(flags, "CompileCallDebugBreak");
1522 if (!maybe_result->ToObject(&result)) return maybe_result;
1523 }
1524 Code* code = Code::cast(result);
1525 USE(code);
1526 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1527 USE(kind);
Steve Block44f0eee2011-05-26 01:26:41 +01001528 PROFILE(isolate(),
Ben Murdoch85b71792012-04-11 18:30:58 +01001529 CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
1530 code, code->arguments_count()));
1531 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001532}
1533
1534
Ben Murdoch85b71792012-04-11 18:30:58 +01001535MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
1536 HandleScope scope(isolate());
1537 // Use the same code for the the step in preparations as we do for
1538 // the miss case.
Steve Blocka7e24c12009-10-30 11:49:00 +00001539 int argc = Code::ExtractArgumentsCountFromFlags(flags);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001540 Code::Kind kind = Code::ExtractKindFromFlags(flags);
1541 if (kind == Code::CALL_IC) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001542 // For the debugger extra ic state is irrelevant.
1543 CallIC::GenerateMiss(masm(), argc, Code::kNoExtraICState);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001544 } else {
1545 KeyedCallIC::GenerateMiss(masm(), argc);
1546 }
Ben Murdoch85b71792012-04-11 18:30:58 +01001547 Object* result;
1548 { MaybeObject* maybe_result =
1549 GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1550 if (!maybe_result->ToObject(&result)) return maybe_result;
1551 }
1552 Code* code = Code::cast(result);
1553 USE(code);
Steve Block44f0eee2011-05-26 01:26:41 +01001554 PROFILE(isolate(),
1555 CodeCreateEvent(
1556 CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
Ben Murdoch85b71792012-04-11 18:30:58 +01001557 code,
Steve Block44f0eee2011-05-26 01:26:41 +01001558 code->arguments_count()));
Ben Murdoch85b71792012-04-11 18:30:58 +01001559 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001560}
Ben Murdoch85b71792012-04-11 18:30:58 +01001561#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001562
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001563#undef CALL_LOGGER_TAG
Steve Blocka7e24c12009-10-30 11:49:00 +00001564
Ben Murdoch85b71792012-04-11 18:30:58 +01001565MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001566 const char* name) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001567 // Check for allocation failures during stub compilation.
1568 if (failure_->IsFailure()) return failure_;
1569
Steve Blocka7e24c12009-10-30 11:49:00 +00001570 // Create code object in the heap.
1571 CodeDesc desc;
1572 masm_.GetCode(&desc);
Ben Murdoch85b71792012-04-11 18:30:58 +01001573 MaybeObject* result = heap()->CreateCode(desc, flags, masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +00001574#ifdef ENABLE_DISASSEMBLER
Ben Murdoch85b71792012-04-11 18:30:58 +01001575 if (FLAG_print_code_stubs && !result->IsFailure()) {
1576 Code::cast(result->ToObjectUnchecked())->Disassemble(name);
1577 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001578#endif
Ben Murdoch85b71792012-04-11 18:30:58 +01001579 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001580}
1581
1582
Ben Murdoch85b71792012-04-11 18:30:58 +01001583MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
1584 if (FLAG_print_code_stubs && (name != NULL)) {
1585 return GetCodeWithFlags(flags, *name->ToCString());
1586 }
1587 return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
Steve Blocka7e24c12009-10-30 11:49:00 +00001588}
1589
Andrei Popescu402d9372010-02-26 13:31:12 +00001590
Ben Murdoch85b71792012-04-11 18:30:58 +01001591void StubCompiler::LookupPostInterceptor(JSObject* holder,
1592 String* name,
Leon Clarke4515c472010-02-03 11:58:03 +00001593 LookupResult* lookup) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001594 holder->LocalLookupRealNamedProperty(name, lookup);
1595 if (!lookup->IsProperty()) {
1596 lookup->NotFound();
1597 Object* proto = holder->GetPrototype();
1598 if (!proto->IsNull()) {
1599 proto->Lookup(name, lookup);
1600 }
1601 }
Leon Clarke4515c472010-02-03 11:58:03 +00001602}
1603
1604
Ben Murdoch85b71792012-04-11 18:30:58 +01001605
1606MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001607 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
Ben Murdoch85b71792012-04-11 18:30:58 +01001608 MaybeObject* result = GetCodeWithFlags(flags, name);
1609 if (!result->IsFailure()) {
1610 PROFILE(isolate(),
1611 CodeCreateEvent(Logger::LOAD_IC_TAG,
1612 Code::cast(result->ToObjectUnchecked()),
1613 name));
1614 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1615 name,
1616 Code::cast(result->ToObjectUnchecked())));
1617 }
1618 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001619}
1620
1621
Ben Murdoch85b71792012-04-11 18:30:58 +01001622MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type,
1623 String* name,
Ben Murdoch257744e2011-11-30 15:57:28 +00001624 InlineCacheState state) {
1625 Code::Flags flags = Code::ComputeFlags(
Ben Murdoch589d6972011-11-30 16:04:58 +00001626 Code::KEYED_LOAD_IC, state, Code::kNoExtraICState, type);
Ben Murdoch85b71792012-04-11 18:30:58 +01001627 MaybeObject* result = GetCodeWithFlags(flags, name);
1628 if (!result->IsFailure()) {
1629 PROFILE(isolate(),
1630 CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
1631 Code::cast(result->ToObjectUnchecked()),
1632 name));
1633 GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1634 name,
1635 Code::cast(result->ToObjectUnchecked())));
1636 }
1637 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001638}
1639
1640
Ben Murdoch85b71792012-04-11 18:30:58 +01001641MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001642 Code::Flags flags =
1643 Code::ComputeMonomorphicFlags(Code::STORE_IC, type, strict_mode_);
Ben Murdoch85b71792012-04-11 18:30:58 +01001644 MaybeObject* result = GetCodeWithFlags(flags, name);
1645 if (!result->IsFailure()) {
1646 PROFILE(isolate(),
1647 CodeCreateEvent(Logger::STORE_IC_TAG,
1648 Code::cast(result->ToObjectUnchecked()),
1649 name));
1650 GDBJIT(AddCode(GDBJITInterface::STORE_IC,
1651 name,
1652 Code::cast(result->ToObjectUnchecked())));
1653 }
1654 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001655}
1656
1657
Ben Murdoch85b71792012-04-11 18:30:58 +01001658MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type,
1659 String* name,
Ben Murdoch257744e2011-11-30 15:57:28 +00001660 InlineCacheState state) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001661 Code::Flags flags =
Ben Murdoch85b71792012-04-11 18:30:58 +01001662 Code::ComputeFlags(Code::KEYED_STORE_IC, state, strict_mode_, type);
1663 MaybeObject* result = GetCodeWithFlags(flags, name);
1664 if (!result->IsFailure()) {
1665 PROFILE(isolate(),
1666 CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
1667 Code::cast(result->ToObjectUnchecked()),
1668 name));
1669 GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC,
1670 name,
1671 Code::cast(result->ToObjectUnchecked())));
1672 }
1673 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001674}
1675
1676
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001677void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
1678 MacroAssembler* masm) {
1679 KeyedStoreIC::GenerateSlow(masm);
1680}
1681
1682
Ben Murdoch85b71792012-04-11 18:30:58 +01001683CallStubCompiler::CallStubCompiler(int argc,
Steve Block8defd9f2010-07-08 12:39:36 +01001684 Code::Kind kind,
Ben Murdoch85b71792012-04-11 18:30:58 +01001685 Code::ExtraICState extra_ic_state,
Steve Block8defd9f2010-07-08 12:39:36 +01001686 InlineCacheHolderFlag cache_holder)
Ben Murdoch85b71792012-04-11 18:30:58 +01001687 : arguments_(argc),
Ben Murdochb8e0da22011-05-16 14:20:40 +01001688 kind_(kind),
Ben Murdoch85b71792012-04-11 18:30:58 +01001689 extra_ic_state_(extra_ic_state),
Ben Murdochb8e0da22011-05-16 14:20:40 +01001690 cache_holder_(cache_holder) {
Steve Block8defd9f2010-07-08 12:39:36 +01001691}
1692
1693
Ben Murdoch85b71792012-04-11 18:30:58 +01001694bool CallStubCompiler::HasCustomCallGenerator(JSFunction* function) {
1695 SharedFunctionInfo* info = function->shared();
1696 if (info->HasBuiltinFunctionId()) {
1697 BuiltinFunctionId id = info->builtin_function_id();
Ben Murdochb0fe1622011-05-05 13:52:32 +01001698#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
Steve Block44f0eee2011-05-26 01:26:41 +01001699 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
Ben Murdochb0fe1622011-05-05 13:52:32 +01001700#undef CALL_GENERATOR_CASE
Steve Block44f0eee2011-05-26 01:26:41 +01001701 }
1702 CallOptimization optimization(function);
Ben Murdoch85b71792012-04-11 18:30:58 +01001703 if (optimization.is_simple_api_call()) {
1704 return true;
1705 }
1706 return false;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001707}
1708
1709
Ben Murdoch85b71792012-04-11 18:30:58 +01001710MaybeObject* CallStubCompiler::CompileCustomCall(Object* object,
1711 JSObject* holder,
1712 JSGlobalPropertyCell* cell,
1713 JSFunction* function,
1714 String* fname) {
Steve Block44f0eee2011-05-26 01:26:41 +01001715 ASSERT(HasCustomCallGenerator(function));
1716
Ben Murdoch85b71792012-04-11 18:30:58 +01001717 SharedFunctionInfo* info = function->shared();
1718 if (info->HasBuiltinFunctionId()) {
1719 BuiltinFunctionId id = info->builtin_function_id();
1720#define CALL_GENERATOR_CASE(name) \
1721 if (id == k##name) { \
1722 return CallStubCompiler::Compile##name##Call(object, \
1723 holder, \
1724 cell, \
1725 function, \
1726 fname); \
Steve Block44f0eee2011-05-26 01:26:41 +01001727 }
1728 CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
Ben Murdochb0fe1622011-05-05 13:52:32 +01001729#undef CALL_GENERATOR_CASE
Steve Block44f0eee2011-05-26 01:26:41 +01001730 }
1731 CallOptimization optimization(function);
1732 ASSERT(optimization.is_simple_api_call());
1733 return CompileFastApiCall(optimization,
1734 object,
1735 holder,
1736 cell,
1737 function,
1738 fname);
Kristian Monsen25f61362010-05-21 11:50:48 +01001739}
1740
1741
Ben Murdoch85b71792012-04-11 18:30:58 +01001742MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001743 int argc = arguments_.immediate();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001744 Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001745 type,
Ben Murdoch85b71792012-04-11 18:30:58 +01001746 extra_ic_state_,
Steve Block8defd9f2010-07-08 12:39:36 +01001747 cache_holder_,
Steve Blocka7e24c12009-10-30 11:49:00 +00001748 argc);
1749 return GetCodeWithFlags(flags, name);
1750}
1751
1752
Ben Murdoch85b71792012-04-11 18:30:58 +01001753MaybeObject* CallStubCompiler::GetCode(JSFunction* function) {
1754 String* function_name = NULL;
Kristian Monsen25f61362010-05-21 11:50:48 +01001755 if (function->shared()->name()->IsString()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001756 function_name = String::cast(function->shared()->name());
Kristian Monsen25f61362010-05-21 11:50:48 +01001757 }
1758 return GetCode(CONSTANT_FUNCTION, function_name);
1759}
1760
1761
Ben Murdoch85b71792012-04-11 18:30:58 +01001762MaybeObject* ConstructStubCompiler::GetCode() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001763 Code::Flags flags = Code::ComputeFlags(Code::STUB);
Ben Murdoch85b71792012-04-11 18:30:58 +01001764 Object* result;
1765 { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ConstructStub");
1766 if (!maybe_result->ToObject(&result)) return maybe_result;
1767 }
1768 Code* code = Code::cast(result);
1769 USE(code);
1770 PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
1771 GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", Code::cast(code)));
1772 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001773}
1774
1775
Steve Block6ded16b2010-05-10 14:33:55 +01001776CallOptimization::CallOptimization(LookupResult* lookup) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001777 if (!lookup->IsProperty() || !lookup->IsCacheable() ||
1778 lookup->type() != CONSTANT_FUNCTION) {
1779 Initialize(NULL);
Ben Murdochc7cc0282012-03-05 14:35:55 +00001780 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +01001781 // We only optimize constant function calls.
1782 Initialize(lookup->GetConstantFunction());
Steve Block6ded16b2010-05-10 14:33:55 +01001783 }
1784}
1785
Ben Murdoch85b71792012-04-11 18:30:58 +01001786CallOptimization::CallOptimization(JSFunction* function) {
Steve Block6ded16b2010-05-10 14:33:55 +01001787 Initialize(function);
1788}
1789
1790
Ben Murdoch85b71792012-04-11 18:30:58 +01001791int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
1792 JSObject* holder) const {
1793 ASSERT(is_simple_api_call_);
1794 if (expected_receiver_type_ == NULL) return 0;
Steve Block6ded16b2010-05-10 14:33:55 +01001795 int depth = 0;
Ben Murdoch85b71792012-04-11 18:30:58 +01001796 while (object != holder) {
1797 if (object->IsInstanceOf(expected_receiver_type_)) return depth;
1798 object = JSObject::cast(object->GetPrototype());
Steve Block6ded16b2010-05-10 14:33:55 +01001799 ++depth;
1800 }
Ben Murdoch85b71792012-04-11 18:30:58 +01001801 if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
Steve Block6ded16b2010-05-10 14:33:55 +01001802 return kInvalidProtoDepth;
1803}
1804
1805
Ben Murdoch85b71792012-04-11 18:30:58 +01001806void CallOptimization::Initialize(JSFunction* function) {
1807 constant_function_ = NULL;
Steve Block6ded16b2010-05-10 14:33:55 +01001808 is_simple_api_call_ = false;
Ben Murdoch85b71792012-04-11 18:30:58 +01001809 expected_receiver_type_ = NULL;
1810 api_call_info_ = NULL;
Steve Block6ded16b2010-05-10 14:33:55 +01001811
Ben Murdoch85b71792012-04-11 18:30:58 +01001812 if (function == NULL || !function->is_compiled()) return;
Steve Block6ded16b2010-05-10 14:33:55 +01001813
1814 constant_function_ = function;
1815 AnalyzePossibleApiFunction(function);
1816}
1817
1818
Ben Murdoch85b71792012-04-11 18:30:58 +01001819void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
1820 SharedFunctionInfo* sfi = function->shared();
1821 if (!sfi->IsApiFunction()) return;
1822 FunctionTemplateInfo* info = sfi->get_api_func_data();
Steve Block6ded16b2010-05-10 14:33:55 +01001823
1824 // Require a C++ callback.
1825 if (info->call_code()->IsUndefined()) return;
Ben Murdoch85b71792012-04-11 18:30:58 +01001826 api_call_info_ = CallHandlerInfo::cast(info->call_code());
Steve Block6ded16b2010-05-10 14:33:55 +01001827
1828 // Accept signatures that either have no restrictions at all or
1829 // only have restrictions on the receiver.
1830 if (!info->signature()->IsUndefined()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001831 SignatureInfo* signature = SignatureInfo::cast(info->signature());
Steve Block6ded16b2010-05-10 14:33:55 +01001832 if (!signature->args()->IsUndefined()) return;
1833 if (!signature->receiver()->IsUndefined()) {
1834 expected_receiver_type_ =
Ben Murdoch85b71792012-04-11 18:30:58 +01001835 FunctionTemplateInfo::cast(signature->receiver());
Steve Block6ded16b2010-05-10 14:33:55 +01001836 }
1837 }
1838
1839 is_simple_api_call_ = true;
1840}
1841
1842
Steve Blocka7e24c12009-10-30 11:49:00 +00001843} } // namespace v8::internal