blob: da6e9c69eafcb6fb5712f73ed5f4d9580e70049a [file] [log] [blame]
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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 "accessors.h"
31#include "api.h"
32#include "arguments.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000033#include "codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000034#include "execution.h"
35#include "ic-inl.h"
36#include "runtime.h"
37#include "stub-cache.h"
38
kasperl@chromium.org71affb52009-05-26 05:44:31 +000039namespace v8 {
40namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041
42#ifdef DEBUG
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000043char IC::TransitionMarkFromState(IC::State state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044 switch (state) {
45 case UNINITIALIZED: return '0';
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000046 case PREMONOMORPHIC: return '.';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047 case MONOMORPHIC: return '1';
48 case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000049 case POLYMORPHIC: return 'P';
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000050 case MEGAMORPHIC: return 'N';
51 case GENERIC: return 'G';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052
53 // We never see the debugger states here, because the state is
54 // computed from the original code - not the patched code. Let
55 // these cases fall through to the unreachable code below.
yangguo@chromium.org9768bf12013-01-11 14:51:07 +000056 case DEBUG_STUB: break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057 }
58 UNREACHABLE();
59 return 0;
60}
61
ulan@chromium.org750145a2013-03-07 15:14:13 +000062
63const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
64 if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
65 if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
66 return ".IGNORE_OOB";
67 }
68 if (IsGrowStoreMode(mode)) return ".GROW";
69 return "";
70}
71
72
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073void IC::TraceIC(const char* type,
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000074 Handle<Object> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000075 if (FLAG_trace_ic) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000076 Code* new_target = raw_target();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000077 State new_state = new_target->ic_state();
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000078 PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000079 StackFrameIterator it(isolate());
ager@chromium.orgea91cc52011-05-23 06:06:11 +000080 while (it.frame()->fp() != this->fp()) it.Advance();
81 StackFrame* raw_frame = it.frame();
82 if (raw_frame->is_internal()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000083 Code* apply_builtin = isolate()->builtins()->builtin(
ager@chromium.orgea91cc52011-05-23 06:06:11 +000084 Builtins::kFunctionApply);
85 if (raw_frame->unchecked_code() == apply_builtin) {
86 PrintF("apply from ");
87 it.Advance();
88 raw_frame = it.frame();
89 }
90 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000091 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
92 Code::ExtraICState extra_state = new_target->extra_ic_state();
ulan@chromium.org750145a2013-03-07 15:14:13 +000093 const char* modifier =
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000094 GetTransitionMarkModifier(Code::GetKeyedAccessStoreMode(extra_state));
ulan@chromium.org65a89c22012-02-14 11:46:07 +000095 PrintF(" (%c->%c%s)",
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000096 TransitionMarkFromState(state()),
ulan@chromium.org65a89c22012-02-14 11:46:07 +000097 TransitionMarkFromState(new_state),
ulan@chromium.org750145a2013-03-07 15:14:13 +000098 modifier);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099 name->Print();
100 PrintF("]\n");
101 }
102}
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000103
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000104#define TRACE_GENERIC_IC(isolate, type, reason) \
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000105 do { \
106 if (FLAG_trace_ic) { \
107 PrintF("[%s patching generic stub in ", type); \
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000108 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000109 PrintF(" (%s)]\n", reason); \
110 } \
111 } while (false)
112
113#else
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000114#define TRACE_GENERIC_IC(isolate, type, reason)
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000115#endif // DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000116
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000117#define TRACE_IC(type, name) \
118 ASSERT((TraceIC(type, name), true))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000119
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000120IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) {
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000121 // To improve the performance of the (much used) IC code, we unfold a few
122 // levels of the stack frame iteration code. This yields a ~35% speedup when
123 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
124 const Address entry =
125 Isolate::c_entry_fp(isolate->thread_local_top());
126 Address* pc_address =
127 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
128 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
129 // If there's another JavaScript frame on the stack or a
130 // StubFailureTrampoline, we need to look one frame further down the stack to
131 // find the frame pointer and the return address stack slot.
132 if (depth == EXTRA_CALL_FRAME) {
133 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
134 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
135 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
136 }
137#ifdef DEBUG
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000138 StackFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000139 for (int i = 0; i < depth + 1; i++) it.Advance();
140 StackFrame* frame = it.frame();
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000141 ASSERT(fp == frame->fp() && pc_address == frame->pc_address());
142#endif
143 fp_ = fp;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000144 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000145 target_ = handle(raw_target(), isolate);
146 state_ = target_->ic_state();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000147}
148
149
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000150#ifdef ENABLE_DEBUGGER_SUPPORT
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000151Address IC::OriginalCodeAddress() const {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000152 HandleScope scope(isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153 // Compute the JavaScript frame for the frame pointer of this IC
154 // structure. We need this to be able to find the function
155 // corresponding to the frame.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000156 StackFrameIterator it(isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000157 while (it.frame()->fp() != this->fp()) it.Advance();
158 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
159 // Find the function on the stack and both the active code for the
160 // function and the original code.
danno@chromium.org169691d2013-07-15 08:01:13 +0000161 JSFunction* function = frame->function();
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000162 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000163 Code* code = shared->code();
164 ASSERT(Debug::HasDebugInfo(shared));
165 Code* original_code = Debug::GetDebugInfo(shared)->original_code();
166 ASSERT(original_code->IsCode());
167 // Get the address of the call site in the active code. This is the
168 // place where the call to DebugBreakXXX is and where the IC
169 // normally would be.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000170 Address addr = Assembler::target_address_from_return_address(pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000171 // Return the address in the original code. This is the place where
ager@chromium.org32912102009-01-16 10:38:43 +0000172 // the call which has been overwritten by the DebugBreakXXX resides
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173 // and the place where the inline cache system should look.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000174 intptr_t delta =
175 original_code->instruction_start() - code->instruction_start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000176 return addr + delta;
177}
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000178#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000179
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000180
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000181static bool HasInterceptorGetter(JSObject* object) {
182 return !object->GetNamedInterceptor()->getter()->IsUndefined();
183}
184
185
186static bool HasInterceptorSetter(JSObject* object) {
187 return !object->GetNamedInterceptor()->setter()->IsUndefined();
188}
189
190
191static void LookupForRead(Handle<Object> object,
192 Handle<String> name,
193 LookupResult* lookup) {
194 // Skip all the objects with named interceptors, but
195 // without actual getter.
196 while (true) {
197 object->Lookup(*name, lookup);
198 // Besides normal conditions (property not found or it's not
199 // an interceptor), bail out if lookup is not cacheable: we won't
200 // be able to IC it anyway and regular lookup should work fine.
201 if (!lookup->IsInterceptor() || !lookup->IsCacheable()) {
202 return;
203 }
204
205 Handle<JSObject> holder(lookup->holder(), lookup->isolate());
206 if (HasInterceptorGetter(*holder)) {
207 return;
208 }
209
210 holder->LocalLookupRealNamedProperty(*name, lookup);
211 if (lookup->IsFound()) {
212 ASSERT(!lookup->IsInterceptor());
213 return;
214 }
215
216 Handle<Object> proto(holder->GetPrototype(), lookup->isolate());
217 if (proto->IsNull()) {
218 ASSERT(!lookup->IsFound());
219 return;
220 }
221
222 object = proto;
223 }
224}
225
226
227bool CallIC::TryUpdateExtraICState(LookupResult* lookup,
228 Handle<Object> object) {
229 if (!lookup->IsConstantFunction()) return false;
230 JSFunction* function = lookup->GetConstantFunction();
231 if (!function->shared()->HasBuiltinFunctionId()) return false;
232
233 // Fetch the arguments passed to the called function.
234 const int argc = target()->arguments_count();
235 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top());
236 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
237 Arguments args(argc + 1,
238 &Memory::Object_at(fp +
239 StandardFrameConstants::kCallerSPOffset +
240 argc * kPointerSize));
241 switch (function->shared()->builtin_function_id()) {
242 case kStringCharCodeAt:
243 case kStringCharAt:
244 if (object->IsString()) {
245 String* string = String::cast(*object);
246 // Check there's the right string value or wrapper in the receiver slot.
247 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value());
248 // If we're in the default (fastest) state and the index is
249 // out of bounds, update the state to record this fact.
250 if (StringStubState::decode(extra_ic_state()) == DEFAULT_STRING_STUB &&
251 argc >= 1 && args[1]->IsNumber()) {
252 double index = DoubleToInteger(args.number_at(1));
253 if (index < 0 || index >= string->length()) {
254 extra_ic_state_ =
255 StringStubState::update(extra_ic_state(),
256 STRING_INDEX_OUT_OF_BOUNDS);
257 return true;
258 }
259 }
260 }
261 break;
262 default:
263 return false;
264 }
265 return false;
266}
267
268
269bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
270 Handle<String> name) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000271 DisallowHeapAllocation no_gc;
272
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000273 if (target()->is_call_stub()) {
274 LookupResult lookup(isolate());
275 LookupForRead(receiver, name, &lookup);
276 if (static_cast<CallIC*>(this)->TryUpdateExtraICState(&lookup, receiver)) {
277 return true;
278 }
279 }
280
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000281 if (target()->is_keyed_stub()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000282 // Determine whether the failure is due to a name failure.
283 if (!name->IsName()) return false;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000284 Name* stub_name = target()->FindFirstName();
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000285 if (*name != stub_name) return false;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000286 }
287
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000288 InlineCacheHolderFlag cache_holder =
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000289 Code::ExtractCacheHolderFromFlags(target()->flags());
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000290
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000291 switch (cache_holder) {
292 case OWN_MAP:
293 // The stub was generated for JSObject but called for non-JSObject.
294 // IC::GetCodeCacheHolder is not applicable.
295 if (!receiver->IsJSObject()) return false;
296 break;
297 case PROTOTYPE_MAP:
298 // IC::GetCodeCacheHolder is not applicable.
299 if (receiver->GetPrototype(isolate())->IsNull()) return false;
300 break;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000301 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000302
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000303 Handle<Map> map(
304 IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000305
306 // Decide whether the inline cache failed because of changes to the
307 // receiver itself or changes to one of its prototypes.
308 //
309 // If there are changes to the receiver itself, the map of the
310 // receiver will have changed and the current target will not be in
311 // the receiver map's code cache. Therefore, if the current target
312 // is in the receiver map's code cache, the inline cache failed due
313 // to prototype check failure.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000314 int index = map->IndexInCodeCache(*name, *target());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000315 if (index >= 0) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000316 map->RemoveFromCodeCache(*name, *target(), index);
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +0000317 // Handlers are stored in addition to the ICs on the map. Remove those, too.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000318 TryRemoveInvalidHandlers(map, name);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000319 return true;
320 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000321
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000322 // The stub is not in the cache. We've ruled out all other kinds of failure
323 // except for proptotype chain changes, a deprecated map, a map that's
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000324 // different from the one that the stub expects, elements kind changes, or a
325 // constant global property that will become mutable. Threat all those
326 // situations as prototype failures (stay monomorphic if possible).
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000327
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000328 // If the IC is shared between multiple receivers (slow dictionary mode), then
329 // the map cannot be deprecated and the stub invalidated.
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000330 if (cache_holder == OWN_MAP) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000331 Map* old_map = target()->FindFirstMap();
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000332 if (old_map == *map) return true;
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000333 if (old_map != NULL) {
334 if (old_map->is_deprecated()) return true;
335 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
336 map->elements_kind())) {
337 return true;
338 }
339 }
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000340 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000341
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000342 if (receiver->IsGlobalObject()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000343 LookupResult lookup(isolate());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000344 GlobalObject* global = GlobalObject::cast(*receiver);
345 global->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000346 if (!lookup.IsFound()) return false;
347 PropertyCell* cell = global->GetPropertyCell(&lookup);
348 return cell->type()->IsConstant();
349 }
350
351 return false;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000352}
353
354
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000355void IC::TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name) {
356 CodeHandleList handlers;
357 target()->FindHandlers(&handlers);
358 for (int i = 0; i < handlers.length(); i++) {
359 Handle<Code> handler = handlers.at(i);
360 int index = map->IndexInCodeCache(*name, *handler);
361 if (index >= 0) {
362 map->RemoveFromCodeCache(*name, *handler, index);
363 return;
364 }
365 }
366}
367
368
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000369void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +0000370 if (!name->IsString()) return;
371 if (state() != MONOMORPHIC) {
372 if (state() == POLYMORPHIC && receiver->IsHeapObject()) {
373 TryRemoveInvalidHandlers(
374 handle(Handle<HeapObject>::cast(receiver)->map()),
375 Handle<String>::cast(name));
376 }
377 return;
378 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000379 if (receiver->IsUndefined() || receiver->IsNull()) return;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000380
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000381 // Remove the target from the code cache if it became invalid
382 // because of changes in the prototype chain to avoid hitting it
383 // again.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000384 if (TryRemoveInvalidPrototypeDependentStub(
385 receiver, Handle<String>::cast(name))) {
386 return MarkMonomorphicPrototypeFailure();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000387 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000388
389 // The builtins object is special. It only changes when JavaScript
390 // builtins are loaded lazily. It is important to keep inline
391 // caches for the builtins object monomorphic. Therefore, if we get
392 // an inline cache miss for the builtins object after lazily loading
ager@chromium.org236ad962008-09-25 09:45:57 +0000393 // JavaScript builtins, we return uninitialized as the state to
394 // force the inline cache back to monomorphic state.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000395 if (receiver->IsJSBuiltinsObject()) state_ = UNINITIALIZED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396}
397
398
ager@chromium.org236ad962008-09-25 09:45:57 +0000399RelocInfo::Mode IC::ComputeMode() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 Address addr = address();
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000401 Code* code = Code::cast(isolate()->FindCodeObject(addr));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402 for (RelocIterator it(code, RelocInfo::kCodeTargetMask);
403 !it.done(); it.next()) {
404 RelocInfo* info = it.rinfo();
405 if (info->pc() == addr) return info->rmode();
406 }
407 UNREACHABLE();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000408 return RelocInfo::NONE32;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000409}
410
411
412Failure* IC::TypeError(const char* type,
413 Handle<Object> object,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000414 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 HandleScope scope(isolate());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000416 Handle<Object> args[2] = { key, object };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 Handle<Object> error = isolate()->factory()->NewTypeError(
418 type, HandleVector(args, 2));
419 return isolate()->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420}
421
422
423Failure* IC::ReferenceError(const char* type, Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000424 HandleScope scope(isolate());
425 Handle<Object> error = isolate()->factory()->NewReferenceError(
426 type, HandleVector(&name, 1));
427 return isolate()->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428}
429
430
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000431static int ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state) {
432 bool was_uninitialized =
433 old_state == UNINITIALIZED || old_state == PREMONOMORPHIC;
434 bool is_uninitialized =
435 new_state == UNINITIALIZED || new_state == PREMONOMORPHIC;
436 return (was_uninitialized && !is_uninitialized) ? 1 :
437 (!was_uninitialized && is_uninitialized) ? -1 : 0;
438}
439
440
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000441void IC::PostPatching(Address address, Code* target, Code* old_target) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000442 if (FLAG_type_info_threshold == 0 && !FLAG_watch_ic_patching) {
443 return;
444 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000445 Isolate* isolate = target->GetHeap()->isolate();
446 Code* host = isolate->
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000447 inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
448 if (host->kind() != Code::FUNCTION) return;
449
450 if (FLAG_type_info_threshold > 0 &&
451 old_target->is_inline_cache_stub() &&
452 target->is_inline_cache_stub()) {
453 int delta = ComputeTypeInfoCountDelta(old_target->ic_state(),
454 target->ic_state());
455 // Not all Code objects have TypeFeedbackInfo.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000456 if (host->type_feedback_info()->IsTypeFeedbackInfo() && delta != 0) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000457 TypeFeedbackInfo* info =
458 TypeFeedbackInfo::cast(host->type_feedback_info());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000459 info->change_ic_with_type_info_count(delta);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000460 }
461 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000462 if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
463 TypeFeedbackInfo* info =
464 TypeFeedbackInfo::cast(host->type_feedback_info());
465 info->change_own_type_change_checksum();
466 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000467 if (FLAG_watch_ic_patching) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000468 host->set_profiler_ticks(0);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000469 isolate->runtime_profiler()->NotifyICChanged();
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000470 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000471 // TODO(2029): When an optimized function is patched, it would
472 // be nice to propagate the corresponding type information to its
473 // unoptimized version for the benefit of later inlining.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000474}
475
476
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000477void IC::Clear(Isolate* isolate, Address address) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000478 Code* target = GetTargetAtAddress(address);
479
480 // Don't clear debug break inline cache as it will remove the break point.
verwaest@chromium.orgec6855e2013-08-22 12:26:58 +0000481 if (target->is_debug_stub()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000482
483 switch (target->kind()) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000484 case Code::LOAD_IC: return LoadIC::Clear(isolate, address, target);
485 case Code::KEYED_LOAD_IC:
486 return KeyedLoadIC::Clear(isolate, address, target);
487 case Code::STORE_IC: return StoreIC::Clear(isolate, address, target);
488 case Code::KEYED_STORE_IC:
489 return KeyedStoreIC::Clear(isolate, address, target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000490 case Code::CALL_IC: return CallIC::Clear(address, target);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000491 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000492 case Code::COMPARE_IC: return CompareIC::Clear(isolate, address, target);
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000493 case Code::COMPARE_NIL_IC: return CompareNilIC::Clear(address, target);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000494 case Code::BINARY_OP_IC:
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000495 case Code::TO_BOOLEAN_IC:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000496 // Clearing these is tricky and does not
497 // make any performance difference.
498 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000499 default: UNREACHABLE();
500 }
501}
502
503
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000504void CallICBase::Clear(Address address, Code* target) {
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +0000505 if (IsCleared(target)) return;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000506 bool contextual = CallICBase::Contextual::decode(target->extra_ic_state());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000507 Code* code =
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000508 target->GetIsolate()->stub_cache()->FindCallInitialize(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000509 target->arguments_count(),
danno@chromium.org40cb8782011-05-25 07:58:50 +0000510 contextual ? RelocInfo::CODE_TARGET_CONTEXT : RelocInfo::CODE_TARGET,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000511 target->kind());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512 SetTargetAtAddress(address, code);
513}
514
515
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000516void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target) {
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +0000517 if (IsCleared(target)) return;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000518 // Make sure to also clear the map used in inline fast cases. If we
519 // do not clear these maps, cached code can keep objects alive
520 // through the embedded maps.
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +0000521 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522}
523
524
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000525void LoadIC::Clear(Isolate* isolate, Address address, Code* target) {
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +0000526 if (IsCleared(target)) return;
527 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000528}
529
530
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000531void StoreIC::Clear(Isolate* isolate, Address address, Code* target) {
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +0000532 if (IsCleared(target)) return;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000533 SetTargetAtAddress(address,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000534 *pre_monomorphic_stub(
535 isolate, Code::GetStrictMode(target->extra_ic_state())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536}
537
538
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000539void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target) {
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +0000540 if (IsCleared(target)) return;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000541 SetTargetAtAddress(address,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000542 *pre_monomorphic_stub(
543 isolate, Code::GetStrictMode(target->extra_ic_state())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544}
545
546
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000547void CompareIC::Clear(Isolate* isolate, Address address, Code* target) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000548 ASSERT(target->major_key() == CodeStub::CompareIC);
549 CompareIC::State handler_state;
550 Token::Value op;
551 ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL,
552 &handler_state, &op);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000553 // Only clear CompareICs that can retain objects.
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000554 if (handler_state != KNOWN_OBJECT) return;
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000555 SetTargetAtAddress(address, GetRawUninitialized(isolate, op));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000556 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
557}
558
559
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000560Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000561 Handle<Object> delegate = Execution::GetFunctionDelegate(isolate(), object);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000562
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000563 if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000564 // Patch the receiver and use the delegate as the function to
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000565 // invoke. This is used for invoking objects as if they were functions.
566 const int argc = target()->arguments_count();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000567 StackFrameLocator locator(isolate());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000568 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
569 int index = frame->ComputeExpressionsCount() - (argc + 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000570 frame->SetExpression(index, *object);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000571 }
572
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000573 return delegate;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000574}
575
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000576
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000577void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee,
578 Handle<Object> object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000579 while (callee->IsJSFunctionProxy()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000580 callee = Handle<Object>(JSFunctionProxy::cast(*callee)->call_trap(),
581 isolate());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000582 }
583
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000584 if (callee->IsJSFunction()) {
585 Handle<JSFunction> function = Handle<JSFunction>::cast(callee);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000586 if (!function->shared()->is_classic_mode() || function->IsBuiltin()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000587 // Do not wrap receiver for strict mode functions or for builtins.
588 return;
589 }
590 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000591
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000592 // And only wrap string, number or boolean.
593 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
594 // Change the receiver to the result of calling ToObject on it.
595 const int argc = this->target()->arguments_count();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000596 StackFrameLocator locator(isolate());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000597 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
598 int index = frame->ComputeExpressionsCount() - (argc + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 frame->SetExpression(index, *isolate()->factory()->ToObject(object));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000600 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000601}
602
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000603
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000604static bool MigrateDeprecated(Handle<Object> object) {
605 if (!object->IsJSObject()) return false;
606 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
607 if (!receiver->map()->is_deprecated()) return false;
608 JSObject::MigrateInstance(Handle<JSObject>::cast(object));
609 return true;
610}
611
612
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000613MaybeObject* CallICBase::LoadFunction(Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000614 Handle<String> name) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000615 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000616
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000617 // If the object is undefined or null it's illegal to try to get any
618 // of its properties; throw a TypeError in that case.
619 if (object->IsUndefined() || object->IsNull()) {
620 return TypeError("non_object_property_call", object, name);
621 }
622
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000623 // Check if the name is trivially convertible to an index and get
624 // the element if so.
625 uint32_t index;
626 if (name->AsArrayIndex(&index)) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000627 Handle<Object> result = Object::GetElement(isolate(), object, index);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000628 RETURN_IF_EMPTY_HANDLE(isolate(), result);
629 if (result->IsJSFunction()) return *result;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000630
631 // Try to find a suitable function delegate for the object at hand.
632 result = TryCallAsFunction(result);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000633 if (result->IsJSFunction()) return *result;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000634
635 // Otherwise, it will fail in the lookup step.
636 }
637
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638 // Lookup the property in the object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000639 LookupResult lookup(isolate());
640 LookupForRead(object, name, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000642 if (!lookup.IsFound()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000643 // If the object does not have the requested property, check which
644 // exception we need to throw.
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +0000645 return IsUndeclaredGlobal(object)
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000646 ? ReferenceError("not_defined", name)
647 : TypeError("undefined_method", object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648 }
649
650 // Lookup is valid: Update inline cache and stub cache.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000651 if (use_ic) UpdateCaches(&lookup, object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000652
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000653 // Get the property.
654 PropertyAttributes attr;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000655 Handle<Object> result =
656 Object::GetProperty(object, object, &lookup, name, &attr);
657 RETURN_IF_EMPTY_HANDLE(isolate(), result);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000658
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000659 if (lookup.IsInterceptor() && attr == ABSENT) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660 // If the object does not have the requested property, check which
661 // exception we need to throw.
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +0000662 return IsUndeclaredGlobal(object)
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000663 ? ReferenceError("not_defined", name)
664 : TypeError("undefined_method", object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665 }
666
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000667 ASSERT(!result->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000668
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000669 // Make receiver an object if the callee requires it. Strict mode or builtin
670 // functions do not wrap the receiver, non-strict functions and objects
671 // called as functions do.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000672 ReceiverToObjectIfRequired(result, object);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000673
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000674 if (result->IsJSFunction()) {
675 Handle<JSFunction> function = Handle<JSFunction>::cast(result);
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000676#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000677 // Handle stepping into a function if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000678 Debug* debug = isolate()->debug();
679 if (debug->StepInActive()) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000680 // Protect the result in a handle as the debugger can allocate and might
681 // cause GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000682 debug->HandleStepIn(function, object, fp(), false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000683 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000684#endif
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000685 return *function;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686 }
687
688 // Try to find a suitable function delegate for the object at hand.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000689 result = TryCallAsFunction(result);
690 if (result->IsJSFunction()) return *result;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000691
692 return TypeError("property_not_function", object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000693}
694
695
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000696Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000697 Handle<Object> object,
698 Handle<String> name) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000699 int argc = target()->arguments_count();
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000700 Handle<JSObject> holder(lookup->holder(), isolate());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000701 switch (lookup->type()) {
702 case FIELD: {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000703 PropertyIndex index = lookup->GetFieldIndex();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000704 return isolate()->stub_cache()->ComputeCallField(
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000705 argc, kind_, extra_ic_state(), name, object, holder, index);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000706 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000707 case CONSTANT: {
708 if (!lookup->IsConstantFunction()) return Handle<Code>::null();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000709 // Get the constant function and compute the code stub for this
710 // call; used for rewriting to monomorphic state and making sure
711 // that the code stub is in the stub cache.
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000712 Handle<JSFunction> function(lookup->GetConstantFunction(), isolate());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000713 return isolate()->stub_cache()->ComputeCallConstant(
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000714 argc, kind_, extra_ic_state(), name, object, holder, function);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000715 }
716 case NORMAL: {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000717 // If we return a null handle, the IC will not be patched.
718 if (!object->IsJSObject()) return Handle<Code>::null();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000719 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
720
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000721 if (holder->IsGlobalObject()) {
722 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000723 Handle<PropertyCell> cell(
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000724 global->GetPropertyCell(lookup), isolate());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000725 if (!cell->value()->IsJSFunction()) return Handle<Code>::null();
726 Handle<JSFunction> function(JSFunction::cast(cell->value()));
727 return isolate()->stub_cache()->ComputeCallGlobal(
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000728 argc, kind_, extra_ic_state(), name,
729 receiver, global, cell, function);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000730 } else {
731 // There is only one shared stub for calling normalized
732 // properties. It does not traverse the prototype chain, so the
733 // property must be found in the receiver for the stub to be
734 // applicable.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000735 if (!holder.is_identical_to(receiver)) return Handle<Code>::null();
736 return isolate()->stub_cache()->ComputeCallNormal(
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000737 argc, kind_, extra_ic_state());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000738 }
739 break;
740 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000741 case INTERCEPTOR:
742 ASSERT(HasInterceptorGetter(*holder));
743 return isolate()->stub_cache()->ComputeCallInterceptor(
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000744 argc, kind_, extra_ic_state(), name, object, holder);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000745 default:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000746 return Handle<Code>::null();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000747 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000748}
749
750
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000751Handle<Code> CallICBase::megamorphic_stub() {
752 return isolate()->stub_cache()->ComputeCallMegamorphic(
753 target()->arguments_count(), kind_, extra_ic_state());
754}
755
756
757Handle<Code> CallICBase::pre_monomorphic_stub() {
758 return isolate()->stub_cache()->ComputeCallPreMonomorphic(
759 target()->arguments_count(), kind_, extra_ic_state());
760}
761
762
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000763void CallICBase::UpdateCaches(LookupResult* lookup,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000764 Handle<Object> object,
765 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000766 // Bail out if we didn't find a result.
ager@chromium.org5c838252010-02-19 08:53:10 +0000767 if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000768
769 // Compute the number of arguments.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000770 Handle<Code> code;
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000771 code = state() == UNINITIALIZED
772 ? pre_monomorphic_stub()
773 : ComputeMonomorphicStub(lookup, object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000774
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000775 // If there's no appropriate stub we simply avoid updating the caches.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000776 // TODO(verwaest): Install a slow fallback in this case to avoid not learning,
777 // and deopting Crankshaft code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000778 if (code.is_null()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000779
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000780 Handle<JSObject> cache_object = object->IsJSObject()
781 ? Handle<JSObject>::cast(object)
782 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())),
783 isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000784
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000785 PatchCache(cache_object, name, code);
786 TRACE_IC("CallIC", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000787}
788
789
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000790MaybeObject* KeyedCallIC::LoadFunction(Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000791 Handle<Object> key) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000792 if (key->IsInternalizedString()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000793 return CallICBase::LoadFunction(object, Handle<String>::cast(key));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000794 }
795
796 if (object->IsUndefined() || object->IsNull()) {
797 return TypeError("non_object_property_call", object, key);
798 }
799
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000800 bool use_ic = MigrateDeprecated(object)
801 ? false : FLAG_use_ic && !object->IsAccessCheckNeeded();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000802
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000803 if (use_ic && state() != MEGAMORPHIC) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000804 ASSERT(!object->IsJSGlobalProxy());
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000805 int argc = target()->arguments_count();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000806 Handle<Code> stub = isolate()->stub_cache()->ComputeCallMegamorphic(
807 argc, Code::KEYED_CALL_IC, Code::kNoExtraICState);
808 if (object->IsJSObject()) {
809 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
810 if (receiver->elements()->map() ==
811 isolate()->heap()->non_strict_arguments_elements_map()) {
812 stub = isolate()->stub_cache()->ComputeCallArguments(argc);
813 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000814 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000815 ASSERT(!stub.is_null());
816 set_target(*stub);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000817 TRACE_IC("CallIC", key);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000818 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000819
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000820 Handle<Object> result = GetProperty(isolate(), object, key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000821 RETURN_IF_EMPTY_HANDLE(isolate(), result);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000822
823 // Make receiver an object if the callee requires it. Strict mode or builtin
824 // functions do not wrap the receiver, non-strict functions and objects
825 // called as functions do.
826 ReceiverToObjectIfRequired(result, object);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000827 if (result->IsJSFunction()) return *result;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000828
829 result = TryCallAsFunction(result);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000830 if (result->IsJSFunction()) return *result;
831
832 return TypeError("property_not_function", object, key);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000833}
834
835
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000836MaybeObject* LoadIC::Load(Handle<Object> object,
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000837 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000838 // If the object is undefined or null it's illegal to try to get any
839 // of its properties; throw a TypeError in that case.
840 if (object->IsUndefined() || object->IsNull()) {
841 return TypeError("non_object_property_load", object, name);
842 }
843
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000844 if (FLAG_use_ic) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000845 // Use specialized code for getting the length of strings and
846 // string wrapper objects. The length property of string wrapper
847 // objects is read-only and therefore always returns the length of
848 // the underlying string value. See ECMA-262 15.5.5.1.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000849 if (object->IsStringWrapper() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000850 name->Equals(isolate()->heap()->length_string())) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000851 Handle<Code> stub;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000852 if (state() == UNINITIALIZED) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000853 stub = pre_monomorphic_stub();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000854 } else if (state() == PREMONOMORPHIC || state() == MONOMORPHIC) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000855 StringLengthStub string_length_stub(kind());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000856 stub = string_length_stub.GetCode(isolate());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000857 } else if (state() != MEGAMORPHIC) {
858 ASSERT(state() != GENERIC);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000859 stub = megamorphic_stub();
860 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000861 if (!stub.is_null()) {
862 set_target(*stub);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000863#ifdef DEBUG
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000864 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /stringwrapper]\n");
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000865#endif
ager@chromium.org378b34e2011-01-28 08:04:38 +0000866 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000867 // Get the string if we have a string wrapper object.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000868 String* string = String::cast(JSValue::cast(*object)->value());
869 return Smi::FromInt(string->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000870 }
871
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 // Use specialized code for getting prototype of functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000873 if (object->IsJSFunction() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000874 name->Equals(isolate()->heap()->prototype_string()) &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000875 Handle<JSFunction>::cast(object)->should_have_prototype()) {
876 Handle<Code> stub;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000877 if (state() == UNINITIALIZED) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000878 stub = pre_monomorphic_stub();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000879 } else if (state() == PREMONOMORPHIC) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000880 FunctionPrototypeStub function_prototype_stub(kind());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000881 stub = function_prototype_stub.GetCode(isolate());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000882 } else if (state() != MEGAMORPHIC) {
883 ASSERT(state() != GENERIC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000884 stub = megamorphic_stub();
885 }
886 if (!stub.is_null()) {
887 set_target(*stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000888#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000889 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890#endif
ager@chromium.org378b34e2011-01-28 08:04:38 +0000891 }
rossberg@chromium.orgebeba022013-08-19 09:36:44 +0000892 return *Accessors::FunctionGetPrototype(Handle<JSFunction>::cast(object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000893 }
894 }
895
896 // Check if the name is trivially convertible to an index and get
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000897 // the element or char if so.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000898 uint32_t index;
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000899 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
900 // Rewrite to the generic keyed load stub.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000901 if (FLAG_use_ic) set_target(*generic_stub());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000902 return Runtime::GetElementOrCharAtOrFail(isolate(), object, index);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000903 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000905 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000906
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000907 // Named lookup in the object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000908 LookupResult lookup(isolate());
909 LookupForRead(object, name, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000910
ager@chromium.org5c838252010-02-19 08:53:10 +0000911 // If we did not find a property, check if we need to throw an exception.
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000912 if (!lookup.IsFound()) {
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +0000913 if (IsUndeclaredGlobal(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914 return ReferenceError("not_defined", name);
915 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000916 LOG(isolate(), SuspectReadEvent(*name, *object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000917 }
918
919 // Update inline cache and stub cache.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000920 if (use_ic) UpdateCaches(&lookup, object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000921
922 PropertyAttributes attr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923 // Get the property.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000924 Handle<Object> result =
925 Object::GetProperty(object, object, &lookup, name, &attr);
926 RETURN_IF_EMPTY_HANDLE(isolate(), result);
927 // If the property is not present, check if we need to throw an
928 // exception.
929 if ((lookup.IsInterceptor() || lookup.IsHandler()) &&
930 attr == ABSENT && IsUndeclaredGlobal(object)) {
931 return ReferenceError("not_defined", name);
932 }
933 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934}
935
936
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000937static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
938 Handle<Map> new_receiver_map) {
939 ASSERT(!new_receiver_map.is_null());
940 for (int current = 0; current < receiver_maps->length(); ++current) {
941 if (!receiver_maps->at(current).is_null() &&
942 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
943 return false;
944 }
945 }
946 receiver_maps->Add(new_receiver_map);
947 return true;
948}
949
950
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000951bool IC::UpdatePolymorphicIC(Handle<HeapObject> receiver,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000952 Handle<String> name,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000953 Handle<Code> code) {
954 if (!code->is_handler()) return false;
ulan@chromium.org750145a2013-03-07 15:14:13 +0000955
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000956 MapHandleList receiver_maps;
957 CodeHandleList handlers;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000958
danno@chromium.orgf005df62013-04-30 16:36:45 +0000959 int number_of_valid_maps;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000960 int handler_to_overwrite = -1;
961 Handle<Map> new_receiver_map(receiver->map());
ulan@chromium.org750145a2013-03-07 15:14:13 +0000962 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000963 DisallowHeapAllocation no_gc;
ulan@chromium.org750145a2013-03-07 15:14:13 +0000964 target()->FindAllMaps(&receiver_maps);
965 int number_of_maps = receiver_maps.length();
danno@chromium.orgf005df62013-04-30 16:36:45 +0000966 number_of_valid_maps = number_of_maps;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000967
danno@chromium.orgf005df62013-04-30 16:36:45 +0000968 for (int i = 0; i < number_of_maps; i++) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000969 Handle<Map> map = receiver_maps.at(i);
970 // Filter out deprecated maps to ensure its instances get migrated.
971 if (map->is_deprecated()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000972 number_of_valid_maps--;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000973 // If the receiver map is already in the polymorphic IC, this indicates
974 // there was a prototoype chain failure. In that case, just overwrite the
975 // handler.
976 } else if (map.is_identical_to(new_receiver_map)) {
977 number_of_valid_maps--;
978 handler_to_overwrite = i;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000979 }
980 }
981
982 if (number_of_valid_maps >= 4) return false;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000983 if (number_of_maps == 0) return false;
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +0000984
985 if (!target()->FindHandlers(&handlers, receiver_maps.length())) {
986 return false;
987 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000988 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000989
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000990 number_of_valid_maps++;
991 if (handler_to_overwrite >= 0) {
992 handlers.Set(handler_to_overwrite, code);
993 } else {
994 receiver_maps.Add(new_receiver_map);
995 handlers.Add(code);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000996 }
997
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000998 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
999 &receiver_maps, &handlers, number_of_valid_maps, name, strict_mode());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001000 set_target(*ic);
1001 return true;
1002}
1003
1004
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001005void IC::UpdateMonomorphicIC(Handle<HeapObject> receiver,
1006 Handle<Code> handler,
1007 Handle<String> name) {
1008 if (!handler->is_handler()) return set_target(*handler);
1009 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
1010 receiver, handler, name, strict_mode());
danno@chromium.orgbee51992013-07-10 14:57:15 +00001011 set_target(*ic);
1012}
1013
1014
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001015void IC::CopyICToMegamorphicCache(Handle<String> name) {
1016 MapHandleList receiver_maps;
1017 CodeHandleList handlers;
1018 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001019 DisallowHeapAllocation no_gc;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001020 target()->FindAllMaps(&receiver_maps);
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +00001021 if (!target()->FindHandlers(&handlers, receiver_maps.length())) return;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001022 }
1023 for (int i = 0; i < receiver_maps.length(); i++) {
1024 UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i));
1025 }
1026}
1027
1028
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001029bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001030 DisallowHeapAllocation no_allocation;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001031
1032 Map* current_map = target()->FindFirstMap();
1033 ElementsKind receiver_elements_kind = receiver_map->elements_kind();
1034 bool more_general_transition =
1035 IsMoreGeneralElementsKindTransition(
1036 current_map->elements_kind(), receiver_elements_kind);
1037 Map* transitioned_map = more_general_transition
1038 ? current_map->LookupElementsTransitionMap(receiver_elements_kind)
1039 : NULL;
1040
1041 return transitioned_map == receiver_map;
1042}
1043
1044
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001045void IC::PatchCache(Handle<HeapObject> receiver,
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001046 Handle<String> name,
1047 Handle<Code> code) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001048 switch (state()) {
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001049 case UNINITIALIZED:
1050 case PREMONOMORPHIC:
1051 case MONOMORPHIC_PROTOTYPE_FAILURE:
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001052 UpdateMonomorphicIC(receiver, code, name);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001053 break;
1054 case MONOMORPHIC:
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001055 // For now, call stubs are allowed to rewrite to the same stub. This
1056 // happens e.g., when the field does not contain a function.
1057 ASSERT(target()->is_call_stub() ||
1058 target()->is_keyed_call_stub() ||
1059 !target().is_identical_to(code));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001060 if (!target()->is_keyed_stub()) {
1061 bool is_same_handler = false;
1062 {
1063 DisallowHeapAllocation no_allocation;
1064 Code* old_handler = target()->FindFirstHandler();
1065 is_same_handler = old_handler == *code;
1066 }
1067 if (is_same_handler
1068 && IsTransitionedMapOfMonomorphicTarget(receiver->map())) {
1069 UpdateMonomorphicIC(receiver, code, name);
1070 break;
1071 }
1072 if (UpdatePolymorphicIC(receiver, name, code)) {
1073 break;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001074 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001075
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001076 CopyICToMegamorphicCache(name);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001077 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001078
1079 UpdateMegamorphicCache(receiver->map(), *name, *code);
1080 set_target(*megamorphic_stub());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001081 break;
1082 case MEGAMORPHIC:
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001083 UpdateMegamorphicCache(receiver->map(), *name, *code);
1084 break;
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001085 case POLYMORPHIC:
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001086 if (target()->is_keyed_stub()) {
1087 // When trying to patch a polymorphic keyed stub with anything other
1088 // than another polymorphic stub, go generic.
1089 set_target(*generic_stub());
1090 } else {
1091 if (UpdatePolymorphicIC(receiver, name, code)) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001092 break;
1093 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001094 CopyICToMegamorphicCache(name);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001095 UpdateMegamorphicCache(receiver->map(), *name, *code);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001096 set_target(*megamorphic_stub());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001097 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001098 break;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001099 case DEBUG_STUB:
1100 break;
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001101 case GENERIC:
1102 UNREACHABLE();
1103 break;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001104 }
1105}
1106
1107
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001108Handle<Code> LoadIC::SimpleFieldLoad(int offset,
1109 bool inobject,
1110 Representation representation) {
1111 if (kind() == Code::LOAD_IC) {
1112 LoadFieldStub stub(inobject, offset, representation);
1113 return stub.GetCode(isolate());
1114 } else {
1115 KeyedLoadFieldStub stub(inobject, offset, representation);
1116 return stub.GetCode(isolate());
1117 }
1118}
1119
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001120void LoadIC::UpdateCaches(LookupResult* lookup,
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001121 Handle<Object> object,
1122 Handle<String> name) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001123 // TODO(verwaest): It would be nice to support loading fields from smis as
1124 // well. For now just fail to update the cache.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001125 if (!object->IsHeapObject()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001126
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001127 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001128
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001129 Handle<Code> code;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001130 if (state() == UNINITIALIZED) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001131 // This is the first time we execute this inline cache.
1132 // Set the target to the pre monomorphic stub to delay
1133 // setting the monomorphic state.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001134 code = pre_monomorphic_stub();
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001135 } else if (!lookup->IsCacheable()) {
1136 // Bail out if the result is not cacheable.
1137 code = slow_stub();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001138 } else if (object->IsString() &&
1139 name->Equals(isolate()->heap()->length_string())) {
1140 int length_index = String::kLengthOffset / kPointerSize;
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001141 code = SimpleFieldLoad(length_index);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001142 } else if (!object->IsJSObject()) {
1143 // TODO(jkummerow): It would be nice to support non-JSObjects in
1144 // ComputeLoadHandler, then we wouldn't need to go generic here.
1145 code = slow_stub();
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001146 } else if (!lookup->IsProperty()) {
1147 code = kind() == Code::LOAD_IC
1148 ? isolate()->stub_cache()->ComputeLoadNonexistent(
1149 name, Handle<JSObject>::cast(receiver))
1150 : slow_stub();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 } else {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001152 code = ComputeHandler(lookup, Handle<JSObject>::cast(receiver), name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001153 }
1154
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001155 PatchCache(receiver, name, code);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001156 TRACE_IC("LoadIC", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157}
1158
1159
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001160void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001161 // Cache code holding map should be consistent with
1162 // GenerateMonomorphicCacheProbe.
1163 isolate()->stub_cache()->Set(name, map, code);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001164}
1165
1166
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001167Handle<Code> IC::ComputeHandler(LookupResult* lookup,
1168 Handle<JSObject> receiver,
1169 Handle<String> name,
1170 Handle<Object> value) {
1171 Handle<Code> code = isolate()->stub_cache()->FindHandler(
1172 name, receiver, kind());
1173 if (!code.is_null()) return code;
1174
1175 code = CompileHandler(lookup, receiver, name, value);
1176
1177 if (code->is_handler() && code->type() != Code::NORMAL) {
1178 HeapObject::UpdateMapCodeCache(receiver, name, code);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001179 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001180
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001181 return code;
1182}
1183
1184
1185Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
1186 Handle<JSObject> receiver,
1187 Handle<String> name,
1188 Handle<Object> unused) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001189 Handle<JSObject> holder(lookup->holder());
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001190 LoadStubCompiler compiler(isolate(), kind());
1191
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001192 switch (lookup->type()) {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001193 case FIELD: {
1194 PropertyIndex field = lookup->GetFieldIndex();
1195 if (receiver.is_identical_to(holder)) {
1196 return SimpleFieldLoad(field.translate(holder),
1197 field.is_inobject(holder),
1198 lookup->representation());
1199 }
1200 return compiler.CompileLoadField(
1201 receiver, holder, name, field, lookup->representation());
1202 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001203 case CONSTANT: {
1204 Handle<Object> constant(lookup->GetConstant(), isolate());
1205 // TODO(2803): Don't compute a stub for cons strings because they cannot
1206 // be embedded into code.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001207 if (constant->IsConsString()) break;
1208 return compiler.CompileLoadConstant(receiver, holder, name, constant);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001209 }
1210 case NORMAL:
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001211 if (kind() != Code::LOAD_IC) break;
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001212 if (holder->IsGlobalObject()) {
1213 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001214 Handle<PropertyCell> cell(
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001215 global->GetPropertyCell(lookup), isolate());
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001216 // TODO(verwaest): Turn into a handler.
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001217 return isolate()->stub_cache()->ComputeLoadGlobal(
1218 name, receiver, global, cell, lookup->IsDontDelete());
1219 }
1220 // There is only one shared stub for loading normalized
1221 // properties. It does not traverse the prototype chain, so the
1222 // property must be found in the receiver for the stub to be
1223 // applicable.
1224 if (!holder.is_identical_to(receiver)) break;
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001225 return isolate()->builtins()->LoadIC_Normal();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001226 case CALLBACKS: {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001227 // Use simple field loads for some well-known callback properties.
1228 int object_offset;
1229 Handle<Map> map(receiver->map());
1230 if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
1231 PropertyIndex index =
1232 PropertyIndex::NewHeaderIndex(object_offset / kPointerSize);
1233 return compiler.CompileLoadField(
1234 receiver, receiver, name, index, Representation::Tagged());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001235 }
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00001236
1237 Handle<Object> callback(lookup->GetCallbackObject(), isolate());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001238 if (callback->IsExecutableAccessorInfo()) {
1239 Handle<ExecutableAccessorInfo> info =
1240 Handle<ExecutableAccessorInfo>::cast(callback);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001241 if (v8::ToCData<Address>(info->getter()) == 0) break;
1242 if (!info->IsCompatibleReceiver(*receiver)) break;
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001243 return compiler.CompileLoadCallback(receiver, holder, name, info);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001244 } else if (callback->IsAccessorPair()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001245 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(),
1246 isolate());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001247 if (!getter->IsJSFunction()) break;
1248 if (holder->IsGlobalObject()) break;
1249 if (!holder->HasFastProperties()) break;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001250 Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
1251 CallOptimization call_optimization(function);
1252 if (call_optimization.is_simple_api_call() &&
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001253 call_optimization.IsCompatibleReceiver(*receiver)) {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001254 return compiler.CompileLoadCallback(
1255 receiver, holder, name, call_optimization);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001256 }
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001257 return compiler.CompileLoadViaGetter(receiver, holder, name, function);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001258 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001259 // TODO(dcarney): Handle correctly.
1260 if (callback->IsDeclaredAccessorInfo()) break;
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001261 ASSERT(callback->IsForeign());
1262 // No IC support for old-style native accessors.
1263 break;
1264 }
1265 case INTERCEPTOR:
1266 ASSERT(HasInterceptorGetter(*holder));
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001267 return compiler.CompileLoadInterceptor(receiver, holder, name);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001268 default:
1269 break;
1270 }
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001271
1272 return slow_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001273}
1274
1275
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001276static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1277 // This helper implements a few common fast cases for converting
1278 // non-smi keys of keyed loads/stores to a smi or a string.
1279 if (key->IsHeapNumber()) {
1280 double value = Handle<HeapNumber>::cast(key)->value();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001281 if (std::isnan(value)) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001282 key = isolate->factory()->nan_string();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001283 } else {
1284 int int_value = FastD2I(value);
1285 if (value == int_value && Smi::IsValid(int_value)) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001286 key = Handle<Smi>(Smi::FromInt(int_value), isolate);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001287 }
1288 }
1289 } else if (key->IsUndefined()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001290 key = isolate->factory()->undefined_string();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001291 }
1292 return key;
1293}
1294
1295
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001296Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001297 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1298 // via megamorphic stubs, since they don't have a map in their relocation info
1299 // and so the stubs can't be harvested for the object needed for a map check.
1300 if (target()->type() != Code::NORMAL) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001301 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type");
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001302 return generic_stub();
1303 }
1304
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001305 Handle<Map> receiver_map(receiver->map(), isolate());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001306 MapHandleList target_receiver_maps;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001307 if (state() == UNINITIALIZED || state() == PREMONOMORPHIC) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001308 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
1309 // yet will do so and stay there.
1310 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1311 }
1312
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001313 if (target().is_identical_to(string_stub())) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001314 target_receiver_maps.Add(isolate()->factory()->string_map());
1315 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001316 target()->FindAllMaps(&target_receiver_maps);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001317 if (target_receiver_maps.length() == 0) {
1318 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1319 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001320 }
1321
1322 // The first time a receiver is seen that is a transitioned version of the
1323 // previous monomorphic receiver type, assume the new ElementsKind is the
1324 // monomorphic type. This benefits global arrays that only transition
1325 // once, and all call sites accessing them are faster if they remain
1326 // monomorphic. If this optimistic assumption is not true, the IC will
1327 // miss again and it will become polymorphic and support both the
1328 // untransitioned and transitioned maps.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001329 if (state() == MONOMORPHIC &&
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001330 IsMoreGeneralElementsKindTransition(
1331 target_receiver_maps.at(0)->elements_kind(),
1332 receiver->GetElementsKind())) {
1333 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1334 }
1335
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001336 ASSERT(state() != GENERIC);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001337
1338 // Determine the list of receiver maps that this call site has seen,
1339 // adding the map that was just encountered.
1340 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1341 // If the miss wasn't due to an unseen map, a polymorphic stub
1342 // won't help, use the generic stub.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001343 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice");
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001344 return generic_stub();
1345 }
1346
1347 // If the maximum number of receiver maps has been exceeded, use the generic
1348 // version of the IC.
1349 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001350 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded");
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001351 return generic_stub();
1352 }
1353
1354 return isolate()->stub_cache()->ComputeLoadElementPolymorphic(
1355 &target_receiver_maps);
1356}
1357
1358
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001359MaybeObject* KeyedLoadIC::Load(Handle<Object> object,
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001360 Handle<Object> key,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001361 ICMissMode miss_mode) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001362 if (MigrateDeprecated(object)) {
1363 return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
1364 }
1365
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001366 // Check for values that can be converted into an internalized string directly
1367 // or is representable as a smi.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001368 key = TryConvertKey(key, isolate());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001369
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001370 if (key->IsInternalizedString()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001371 return LoadIC::Load(object, Handle<String>::cast(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372 }
1373
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001374 if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
1375 ASSERT(!object->IsJSGlobalProxy());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001376 Handle<Code> stub = generic_stub();
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001377 if (miss_mode == MISS_FORCE_GENERIC) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001378 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "force generic");
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001379 } else if (object->IsString() && key->IsNumber()) {
1380 if (state() == UNINITIALIZED) stub = string_stub();
1381 } else if (object->IsJSObject()) {
1382 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1383 if (receiver->elements()->map() ==
1384 isolate()->heap()->non_strict_arguments_elements_map()) {
1385 stub = non_strict_arguments_stub();
1386 } else if (receiver->HasIndexedInterceptor()) {
1387 stub = indexed_interceptor_stub();
1388 } else if (!key->ToSmi()->IsFailure() &&
1389 (!target().is_identical_to(non_strict_arguments_stub()))) {
1390 stub = LoadElementStub(receiver);
1391 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001392 }
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001393
1394 ASSERT(!stub.is_null());
1395 set_target(*stub);
1396 TRACE_IC("LoadIC", key);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001397 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00001400 return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001401}
1402
1403
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001404static bool LookupForWrite(Handle<JSObject> receiver,
1405 Handle<String> name,
danno@chromium.orgf005df62013-04-30 16:36:45 +00001406 Handle<Object> value,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001407 LookupResult* lookup,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001408 IC* ic) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001409 Handle<JSObject> holder = receiver;
1410 receiver->Lookup(*name, lookup);
1411 if (lookup->IsFound()) {
1412 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
1413
1414 if (lookup->holder() == *receiver) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001415 if (lookup->IsInterceptor() && !HasInterceptorSetter(*receiver)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001416 receiver->LocalLookupRealNamedProperty(*name, lookup);
1417 return lookup->IsFound() &&
1418 !lookup->IsReadOnly() &&
danno@chromium.orgf005df62013-04-30 16:36:45 +00001419 lookup->CanHoldValue(value) &&
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001420 lookup->IsCacheable();
1421 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001422 return lookup->CanHoldValue(value);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001423 }
1424
1425 if (lookup->IsPropertyCallbacks()) return true;
1426
1427 // Currently normal holders in the prototype chain are not supported. They
1428 // would require a runtime positive lookup and verification that the details
1429 // have not changed.
1430 if (lookup->IsInterceptor() || lookup->IsNormal()) return false;
1431 holder = Handle<JSObject>(lookup->holder(), lookup->isolate());
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001432 }
1433
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001434 // While normally LookupTransition gets passed the receiver, in this case we
1435 // pass the holder of the property that we overwrite. This keeps the holder in
1436 // the LookupResult intact so we can later use it to generate a prototype
1437 // chain check. This avoids a double lookup, but requires us to pass in the
1438 // receiver when trying to fetch extra information from the transition.
1439 receiver->map()->LookupTransition(*holder, *name, lookup);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001440 if (!lookup->IsTransition()) return false;
1441 PropertyDetails target_details =
1442 lookup->GetTransitionDetails(receiver->map());
1443 if (target_details.IsReadOnly()) return false;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001444
1445 // If the value that's being stored does not fit in the field that the
1446 // instance would transition to, create a new transition that fits the value.
1447 // This has to be done before generating the IC, since that IC will embed the
1448 // transition target.
1449 // Ensure the instance and its map were migrated before trying to update the
1450 // transition target.
1451 ASSERT(!receiver->map()->is_deprecated());
1452 if (!value->FitsRepresentation(target_details.representation())) {
1453 Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map()));
1454 Map::GeneralizeRepresentation(
rossberg@chromium.org92597162013-08-23 13:28:00 +00001455 target, target->LastAdded(),
1456 value->OptimalRepresentation(), FORCE_FIELD);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001457 // Lookup the transition again since the transition tree may have changed
1458 // entirely by the migration above.
1459 receiver->map()->LookupTransition(*holder, *name, lookup);
1460 if (!lookup->IsTransition()) return false;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001461 ic->MarkMonomorphicPrototypeFailure();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001462 }
1463 return true;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001464}
1465
1466
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001467MaybeObject* StoreIC::Store(Handle<Object> object,
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001468 Handle<String> name,
1469 Handle<Object> value,
1470 JSReceiver::StoreFromKeyed store_mode) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001471 if (MigrateDeprecated(object) || object->IsJSProxy()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001472 Handle<Object> result = JSReceiver::SetProperty(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001473 Handle<JSReceiver>::cast(object), name, value, NONE, strict_mode());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001474 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1475 return *result;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001476 }
1477
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001478 // If the object is undefined or null it's illegal to try to set any
1479 // properties on it; throw a TypeError in that case.
1480 if (object->IsUndefined() || object->IsNull()) {
1481 return TypeError("non_object_property_store", object, name);
1482 }
1483
1484 // The length property of string values is read-only. Throw in strict mode.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001485 if (strict_mode() == kStrictMode && object->IsString() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001486 name->Equals(isolate()->heap()->length_string())) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001487 return TypeError("strict_read_only_property", object, name);
1488 }
1489
1490 // Ignore other stores where the receiver is not a JSObject.
1491 // TODO(1475): Must check prototype chains of object wrappers.
1492 if (!object->IsJSObject()) return *value;
1493
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001494 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1495
1496 // Check if the given name is an array index.
1497 uint32_t index;
1498 if (name->AsArrayIndex(&index)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001499 Handle<Object> result =
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001500 JSObject::SetElement(receiver, index, value, NONE, strict_mode());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001501 RETURN_IF_EMPTY_HANDLE(isolate(), result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 return *value;
1503 }
1504
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001505 // Observed objects are always modified through the runtime.
1506 if (FLAG_harmony_observation && receiver->map()->is_observed()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001507 Handle<Object> result = JSReceiver::SetProperty(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001508 receiver, name, value, NONE, strict_mode(), store_mode);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001509 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1510 return *result;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001511 }
1512
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001513 // Use specialized code for setting the length of arrays with fast
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001514 // properties. Slow properties might indicate redefinition of the length
danno@chromium.org1bc70ab2013-07-14 22:07:11 +00001515 // property. Note that when redefined using Object.freeze, it's possible
1516 // to have fast properties but a read-only length.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001517 if (FLAG_use_ic &&
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001518 receiver->IsJSArray() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001519 name->Equals(isolate()->heap()->length_string()) &&
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001520 Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() &&
danno@chromium.org1bc70ab2013-07-14 22:07:11 +00001521 receiver->HasFastProperties() &&
1522 !receiver->map()->is_frozen()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001523 Handle<Code> stub =
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001524 StoreArrayLengthStub(kind(), strict_mode()).GetCode(isolate());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001525 set_target(*stub);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001526 TRACE_IC("StoreIC", name);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001527 Handle<Object> result = JSReceiver::SetProperty(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001528 receiver, name, value, NONE, strict_mode(), store_mode);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001529 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1530 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 }
1532
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001533 if (receiver->IsJSGlobalProxy()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001534 if (FLAG_use_ic && kind() != Code::KEYED_STORE_IC) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001535 // Generate a generic stub that goes to the runtime when we see a global
1536 // proxy as receiver.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001537 Handle<Code> stub = global_proxy_stub();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001538 set_target(*stub);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001539 TRACE_IC("StoreIC", name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001540 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001541 Handle<Object> result = JSReceiver::SetProperty(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001542 receiver, name, value, NONE, strict_mode(), store_mode);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001543 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1544 return *result;
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001545 }
1546
1547 LookupResult lookup(isolate());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001548 bool can_store = LookupForWrite(receiver, name, value, &lookup, this);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001549 if (!can_store &&
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001550 strict_mode() == kStrictMode &&
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001551 !(lookup.IsProperty() && lookup.IsReadOnly()) &&
1552 IsUndeclaredGlobal(object)) {
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00001553 // Strict mode doesn't allow setting non-existent global property.
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001554 return ReferenceError("not_defined", name);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001555 }
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001556 if (FLAG_use_ic) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001557 if (state() == UNINITIALIZED) {
1558 Handle<Code> stub = pre_monomorphic_stub();
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001559 set_target(*stub);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001560 TRACE_IC("StoreIC", name);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001561 } else if (can_store) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001562 UpdateCaches(&lookup, receiver, name, value);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001563 } else if (!name->IsCacheable(isolate()) ||
1564 lookup.IsNormal() ||
1565 (lookup.IsField() && lookup.CanHoldValue(value))) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001566 Handle<Code> stub = generic_stub();
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001567 set_target(*stub);
1568 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001569 }
1570
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571 // Set the property.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001572 Handle<Object> result = JSReceiver::SetProperty(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001573 receiver, name, value, NONE, strict_mode(), store_mode);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001574 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1575 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576}
1577
1578
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001579void StoreIC::UpdateCaches(LookupResult* lookup,
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001580 Handle<JSObject> receiver,
1581 Handle<String> name,
1582 Handle<Object> value) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001583 ASSERT(!receiver->IsJSGlobalProxy());
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001584 ASSERT(lookup->IsFound());
1585
danno@chromium.orgc612e022011-11-10 11:38:15 +00001586 // These are not cacheable, so we never see such LookupResults here.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001587 ASSERT(!lookup->IsHandler());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001589 Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001591 PatchCache(receiver, name, code);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001592 TRACE_IC("StoreIC", name);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001593}
1594
1595
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001596Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
1597 Handle<JSObject> receiver,
1598 Handle<String> name,
1599 Handle<Object> value) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001600 Handle<JSObject> holder(lookup->holder());
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001601 StoreStubCompiler compiler(isolate(), strict_mode(), kind());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001602 switch (lookup->type()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001603 case FIELD:
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001604 return compiler.CompileStoreField(receiver, lookup, name);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001605 case TRANSITION: {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001606 // Explicitly pass in the receiver map since LookupForWrite may have
1607 // stored something else than the receiver in the holder.
1608 Handle<Map> transition(
1609 lookup->GetTransitionTarget(receiver->map()), isolate());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001610 int descriptor = transition->LastAdded();
1611
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001612 DescriptorArray* target_descriptors = transition->instance_descriptors();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001613 PropertyDetails details = target_descriptors->GetDetails(descriptor);
1614
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001615 if (details.type() == CALLBACKS || details.attributes() != NONE) break;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001616
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001617 return compiler.CompileStoreTransition(
1618 receiver, lookup, transition, name);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001619 }
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001620 case NORMAL:
1621 if (kind() == Code::KEYED_STORE_IC) break;
1622 if (receiver->IsGlobalObject()) {
1623 // The stub generated for the global object picks the value directly
1624 // from the property cell. So the property must be directly on the
1625 // global object.
1626 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
1627 Handle<PropertyCell> cell(
1628 global->GetPropertyCell(lookup), isolate());
1629 // TODO(verwaest): Turn into a handler.
1630 return isolate()->stub_cache()->ComputeStoreGlobal(
1631 name, global, cell, value, strict_mode());
1632 }
1633 ASSERT(holder.is_identical_to(receiver));
1634 return strict_mode() == kStrictMode
1635 ? isolate()->builtins()->StoreIC_Normal_Strict()
1636 : isolate()->builtins()->StoreIC_Normal();
1637 case CALLBACKS: {
1638 if (kind() == Code::KEYED_STORE_IC) break;
1639 Handle<Object> callback(lookup->GetCallbackObject(), isolate());
1640 if (callback->IsExecutableAccessorInfo()) {
1641 Handle<ExecutableAccessorInfo> info =
1642 Handle<ExecutableAccessorInfo>::cast(callback);
1643 if (v8::ToCData<Address>(info->setter()) == 0) break;
1644 if (!holder->HasFastProperties()) break;
1645 if (!info->IsCompatibleReceiver(*receiver)) break;
1646 return compiler.CompileStoreCallback(receiver, holder, name, info);
1647 } else if (callback->IsAccessorPair()) {
1648 Handle<Object> setter(
1649 Handle<AccessorPair>::cast(callback)->setter(), isolate());
1650 if (!setter->IsJSFunction()) break;
1651 if (holder->IsGlobalObject()) break;
1652 if (!holder->HasFastProperties()) break;
1653 Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1654 CallOptimization call_optimization(function);
1655 if (call_optimization.is_simple_api_call() &&
1656 call_optimization.IsCompatibleReceiver(*receiver)) {
1657 return compiler.CompileStoreCallback(
1658 receiver, holder, name, call_optimization);
1659 }
1660 return compiler.CompileStoreViaSetter(
1661 receiver, holder, name, Handle<JSFunction>::cast(setter));
1662 }
1663 // TODO(dcarney): Handle correctly.
1664 if (callback->IsDeclaredAccessorInfo()) break;
1665 ASSERT(callback->IsForeign());
1666 // No IC support for old-style native accessors.
1667 break;
1668 }
1669 case INTERCEPTOR:
1670 if (kind() == Code::KEYED_STORE_IC) break;
1671 ASSERT(HasInterceptorSetter(*receiver));
1672 return compiler.CompileStoreInterceptor(receiver, name);
1673 case CONSTANT:
1674 break;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001675 case NONEXISTENT:
danno@chromium.orgc612e022011-11-10 11:38:15 +00001676 case HANDLER:
danno@chromium.orgc612e022011-11-10 11:38:15 +00001677 UNREACHABLE();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001678 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001679 }
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001680 return slow_stub();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001681}
1682
1683
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001684Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001685 KeyedAccessStoreMode store_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001686 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1687 // via megamorphic stubs, since they don't have a map in their relocation info
1688 // and so the stubs can't be harvested for the object needed for a map check.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001689 if (target()->type() != Code::NORMAL) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001690 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type");
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001691 return generic_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001692 }
1693
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001694 Handle<Map> receiver_map(receiver->map(), isolate());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001695 if (state() == UNINITIALIZED || state() == PREMONOMORPHIC) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001696 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
1697 // yet will do so and stay there.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001698 Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, store_mode);
1699 store_mode = GetNonTransitioningStoreMode(store_mode);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001700 return isolate()->stub_cache()->ComputeKeyedStoreElement(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001701 monomorphic_map, strict_mode(), store_mode);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001702 }
1703
ulan@chromium.org750145a2013-03-07 15:14:13 +00001704 MapHandleList target_receiver_maps;
1705 target()->FindAllMaps(&target_receiver_maps);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001706 if (target_receiver_maps.length() == 0) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001707 // In the case that there is a non-map-specific IC is installed (e.g. keyed
1708 // stores into properties in dictionary mode), then there will be not
1709 // receiver maps in the target.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001710 return generic_stub();
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001711 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001712
1713 // There are several special cases where an IC that is MONOMORPHIC can still
1714 // transition to a different GetNonTransitioningStoreMode IC that handles a
1715 // superset of the original IC. Handle those here if the receiver map hasn't
1716 // changed or it has transitioned to a more general kind.
1717 KeyedAccessStoreMode old_store_mode =
1718 Code::GetKeyedAccessStoreMode(target()->extra_ic_state());
1719 Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001720 if (state() == MONOMORPHIC) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001721 // If the "old" and "new" maps are in the same elements map family, stay
1722 // MONOMORPHIC and use the map for the most generic ElementsKind.
1723 Handle<Map> transitioned_receiver_map = receiver_map;
1724 if (IsTransitionStoreMode(store_mode)) {
1725 transitioned_receiver_map =
1726 ComputeTransitionedMap(receiver, store_mode);
1727 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001728 if (IsTransitionedMapOfMonomorphicTarget(*transitioned_receiver_map)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001729 // Element family is the same, use the "worst" case map.
1730 store_mode = GetNonTransitioningStoreMode(store_mode);
1731 return isolate()->stub_cache()->ComputeKeyedStoreElement(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001732 transitioned_receiver_map, strict_mode(), store_mode);
danno@chromium.org169691d2013-07-15 08:01:13 +00001733 } else if (*previous_receiver_map == receiver->map() &&
1734 old_store_mode == STANDARD_STORE &&
1735 (IsGrowStoreMode(store_mode) ||
1736 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1737 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1738 // A "normal" IC that handles stores can switch to a version that can
1739 // grow at the end of the array, handle OOB accesses or copy COW arrays
1740 // and still stay MONOMORPHIC.
1741 return isolate()->stub_cache()->ComputeKeyedStoreElement(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001742 receiver_map, strict_mode(), store_mode);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001743 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001744 }
1745
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001746 ASSERT(state() != GENERIC);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001747
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001748 bool map_added =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001749 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001750
ulan@chromium.org750145a2013-03-07 15:14:13 +00001751 if (IsTransitionStoreMode(store_mode)) {
1752 Handle<Map> transitioned_receiver_map =
1753 ComputeTransitionedMap(receiver, store_mode);
1754 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1755 transitioned_receiver_map);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001756 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001757
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001758 if (!map_added) {
1759 // If the miss wasn't due to an unseen map, a polymorphic stub
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001760 // won't help, use the generic stub.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001761 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice");
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001762 return generic_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001763 }
1764
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001765 // If the maximum number of receiver maps has been exceeded, use the generic
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001766 // version of the IC.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001767 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001768 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded");
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001769 return generic_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001770 }
1771
ulan@chromium.org750145a2013-03-07 15:14:13 +00001772 // Make sure all polymorphic handlers have the same store mode, otherwise the
1773 // generic stub must be used.
1774 store_mode = GetNonTransitioningStoreMode(store_mode);
1775 if (old_store_mode != STANDARD_STORE) {
1776 if (store_mode == STANDARD_STORE) {
1777 store_mode = old_store_mode;
1778 } else if (store_mode != old_store_mode) {
1779 TRACE_GENERIC_IC(isolate(), "KeyedIC", "store mode mismatch");
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001780 return generic_stub();
ulan@chromium.org750145a2013-03-07 15:14:13 +00001781 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001782 }
1783
jkummerow@chromium.org91efda92013-03-25 16:32:26 +00001784 // If the store mode isn't the standard mode, make sure that all polymorphic
1785 // receivers are either external arrays, or all "normal" arrays. Otherwise,
1786 // use the generic stub.
1787 if (store_mode != STANDARD_STORE) {
1788 int external_arrays = 0;
1789 for (int i = 0; i < target_receiver_maps.length(); ++i) {
1790 if (target_receiver_maps[i]->has_external_array_elements()) {
1791 external_arrays++;
1792 }
1793 }
1794 if (external_arrays != 0 &&
1795 external_arrays != target_receiver_maps.length()) {
1796 TRACE_GENERIC_IC(isolate(), "KeyedIC",
1797 "unsupported combination of external and normal arrays");
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001798 return generic_stub();
jkummerow@chromium.org91efda92013-03-25 16:32:26 +00001799 }
1800 }
1801
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001802 return isolate()->stub_cache()->ComputeStoreElementPolymorphic(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001803 &target_receiver_maps, store_mode, strict_mode());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001804}
1805
1806
ulan@chromium.org750145a2013-03-07 15:14:13 +00001807Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1808 Handle<JSObject> receiver,
1809 KeyedAccessStoreMode store_mode) {
1810 switch (store_mode) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001811 case STORE_TRANSITION_SMI_TO_OBJECT:
1812 case STORE_TRANSITION_DOUBLE_TO_OBJECT:
1813 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
1814 case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001815 return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001816 case STORE_TRANSITION_SMI_TO_DOUBLE:
1817 case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001818 return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001819 case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
1820 case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1821 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
1822 case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001823 return JSObject::GetElementsTransitionMap(receiver,
1824 FAST_HOLEY_ELEMENTS);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001825 case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1826 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001827 return JSObject::GetElementsTransitionMap(receiver,
1828 FAST_HOLEY_DOUBLE_ELEMENTS);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001829 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
1830 ASSERT(receiver->map()->has_external_array_elements());
1831 // Fall through
1832 case STORE_NO_TRANSITION_HANDLE_COW:
1833 case STANDARD_STORE:
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001834 case STORE_AND_GROW_NO_TRANSITION:
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001835 return Handle<Map>(receiver->map(), isolate());
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001836 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001837 return Handle<Map>::null();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001838}
1839
1840
ulan@chromium.org750145a2013-03-07 15:14:13 +00001841bool IsOutOfBoundsAccess(Handle<JSObject> receiver,
1842 int index) {
1843 if (receiver->IsJSArray()) {
1844 return JSArray::cast(*receiver)->length()->IsSmi() &&
1845 index >= Smi::cast(JSArray::cast(*receiver)->length())->value();
1846 }
1847 return index >= receiver->elements()->length();
1848}
1849
1850
1851KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
1852 Handle<Object> key,
1853 Handle<Object> value) {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001854 ASSERT(!key->ToSmi()->IsFailure());
1855 Smi* smi_key = NULL;
1856 key->ToSmi()->To(&smi_key);
1857 int index = smi_key->value();
ulan@chromium.org750145a2013-03-07 15:14:13 +00001858 bool oob_access = IsOutOfBoundsAccess(receiver, index);
1859 bool allow_growth = receiver->IsJSArray() && oob_access;
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001860 if (allow_growth) {
1861 // Handle growing array in stub if necessary.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001862 if (receiver->HasFastSmiElements()) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001863 if (value->IsHeapNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001864 if (receiver->HasFastHoleyElements()) {
1865 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1866 } else {
1867 return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE;
1868 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001869 }
1870 if (value->IsHeapObject()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001871 if (receiver->HasFastHoleyElements()) {
1872 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT;
1873 } else {
1874 return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT;
1875 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001876 }
1877 } else if (receiver->HasFastDoubleElements()) {
1878 if (!value->IsSmi() && !value->IsHeapNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001879 if (receiver->HasFastHoleyElements()) {
1880 return STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
1881 } else {
1882 return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT;
1883 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001884 }
1885 }
1886 return STORE_AND_GROW_NO_TRANSITION;
1887 } else {
1888 // Handle only in-bounds elements accesses.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001889 if (receiver->HasFastSmiElements()) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001890 if (value->IsHeapNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001891 if (receiver->HasFastHoleyElements()) {
1892 return STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1893 } else {
1894 return STORE_TRANSITION_SMI_TO_DOUBLE;
1895 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001896 } else if (value->IsHeapObject()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001897 if (receiver->HasFastHoleyElements()) {
1898 return STORE_TRANSITION_HOLEY_SMI_TO_OBJECT;
1899 } else {
1900 return STORE_TRANSITION_SMI_TO_OBJECT;
1901 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001902 }
1903 } else if (receiver->HasFastDoubleElements()) {
1904 if (!value->IsSmi() && !value->IsHeapNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001905 if (receiver->HasFastHoleyElements()) {
1906 return STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
1907 } else {
1908 return STORE_TRANSITION_DOUBLE_TO_OBJECT;
1909 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001910 }
1911 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001912 if (!FLAG_trace_external_array_abuse &&
1913 receiver->map()->has_external_array_elements() && oob_access) {
1914 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001915 }
1916 Heap* heap = receiver->GetHeap();
1917 if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
1918 return STORE_NO_TRANSITION_HANDLE_COW;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001919 } else {
1920 return STANDARD_STORE;
1921 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001922 }
1923}
1924
1925
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001926MaybeObject* KeyedStoreIC::Store(Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001927 Handle<Object> key,
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001928 Handle<Object> value,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001929 ICMissMode miss_mode) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001930 if (MigrateDeprecated(object)) {
1931 return Runtime::SetObjectPropertyOrFail(
1932 isolate(), object , key, value, NONE, strict_mode());
1933 }
1934
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001935 // Check for values that can be converted into an internalized string directly
1936 // or is representable as a smi.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001937 key = TryConvertKey(key, isolate());
1938
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001939 if (key->IsInternalizedString()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001940 return StoreIC::Store(object,
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001941 Handle<String>::cast(key),
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001942 value,
1943 JSReceiver::MAY_BE_STORE_FROM_KEYED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001944 }
1945
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001946 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() &&
1947 !(FLAG_harmony_observation && object->IsJSObject() &&
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001948 JSObject::cast(*object)->map()->is_observed());
1949 if (use_ic && !object->IsSmi()) {
1950 // Don't use ICs for maps of the objects in Array's prototype chain. We
1951 // expect to be able to trap element sets to objects with those maps in the
1952 // runtime to enable optimization of element hole access.
1953 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
1954 if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false;
1955 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956
ager@chromium.org3811b432009-10-28 14:53:37 +00001957 if (use_ic) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001958 ASSERT(!object->IsJSGlobalProxy());
1959
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001960 Handle<Code> stub = generic_stub();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001961 if (miss_mode != MISS_FORCE_GENERIC) {
1962 if (object->IsJSObject()) {
1963 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001964 bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001965 if (receiver->elements()->map() ==
1966 isolate()->heap()->non_strict_arguments_elements_map()) {
1967 stub = non_strict_arguments_stub();
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001968 } else if (key_is_smi_like &&
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001969 (!target().is_identical_to(non_strict_arguments_stub()))) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001970 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001971 stub = StoreElementStub(receiver, store_mode);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001972 } else {
1973 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "key not a number");
whesse@chromium.org7b260152011-06-20 15:33:18 +00001974 }
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001975 } else {
1976 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "not an object");
ager@chromium.org3811b432009-10-28 14:53:37 +00001977 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001978 } else {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001979 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "force generic");
ager@chromium.org3811b432009-10-28 14:53:37 +00001980 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001981 ASSERT(!stub.is_null());
1982 set_target(*stub);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001983 TRACE_IC("StoreIC", key);
ager@chromium.org3811b432009-10-28 14:53:37 +00001984 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001985
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00001986 return Runtime::SetObjectPropertyOrFail(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001987 isolate(), object , key, value, NONE, strict_mode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001988}
1989
1990
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001991#undef TRACE_IC
1992
1993
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001994// ----------------------------------------------------------------------------
1995// Static IC stub generators.
1996//
1997
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001998// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001999RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002000 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002001 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002002 CallIC ic(isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002003 Handle<Object> receiver = args.at<Object>(0);
2004 Handle<String> key = args.at<String>(1);
2005 ic.UpdateState(receiver, key);
2006 MaybeObject* maybe_result = ic.LoadFunction(receiver, key);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002007 JSFunction* raw_function;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002008 if (!maybe_result->To(&raw_function)) return maybe_result;
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002009
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002010 // The first time the inline cache is updated may be the first time the
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002011 // function it references gets called. If the function is lazily compiled
2012 // then the first call will trigger a compilation. We check for this case
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002013 // and we do the compilation immediately, instead of waiting for the stub
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002014 // currently attached to the JSFunction object to trigger compilation.
2015 if (raw_function->is_compiled()) return raw_function;
2016
2017 Handle<JSFunction> function(raw_function);
2018 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
2019 return *function;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002020}
2021
2022
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002023// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002024RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002025 HandleScope scope(isolate);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002026 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002027 KeyedCallIC ic(isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002028 Handle<Object> receiver = args.at<Object>(0);
2029 Handle<Object> key = args.at<Object>(1);
2030 ic.UpdateState(receiver, key);
2031 MaybeObject* maybe_result = ic.LoadFunction(receiver, key);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002032 // Result could be a function or a failure.
2033 JSFunction* raw_function = NULL;
2034 if (!maybe_result->To(&raw_function)) return maybe_result;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002035
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002036 if (raw_function->is_compiled()) return raw_function;
2037
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002038 Handle<JSFunction> function(raw_function, isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002039 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
2040 return *function;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002041}
2042
2043
2044// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002045RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002046 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002047 ASSERT(args.length() == 2);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002048 LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002049 Handle<Object> receiver = args.at<Object>(0);
2050 Handle<String> key = args.at<String>(1);
2051 ic.UpdateState(receiver, key);
2052 return ic.Load(receiver, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002053}
2054
2055
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002056// Used from ic-<arch>.cc
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002057RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002058 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002059 ASSERT(args.length() == 2);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002060 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002061 Handle<Object> receiver = args.at<Object>(0);
2062 Handle<Object> key = args.at<Object>(1);
2063 ic.UpdateState(receiver, key);
2064 return ic.Load(receiver, key, MISS);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002065}
2066
2067
2068RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure) {
2069 HandleScope scope(isolate);
2070 ASSERT(args.length() == 2);
2071 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002072 Handle<Object> receiver = args.at<Object>(0);
2073 Handle<Object> key = args.at<Object>(1);
2074 ic.UpdateState(receiver, key);
2075 return ic.Load(receiver, key, MISS);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002076}
2077
2078
2079RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002080 HandleScope scope(isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002081 ASSERT(args.length() == 2);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002082 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002083 Handle<Object> receiver = args.at<Object>(0);
2084 Handle<Object> key = args.at<Object>(1);
2085 ic.UpdateState(receiver, key);
2086 return ic.Load(receiver, key, MISS_FORCE_GENERIC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002087}
2088
2089
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002090// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002091RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002092 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002093 ASSERT(args.length() == 3);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002094 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002095 Handle<Object> receiver = args.at<Object>(0);
2096 Handle<String> key = args.at<String>(1);
2097 ic.UpdateState(receiver, key);
2098 return ic.Store(receiver, key, args.at<Object>(2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002099}
2100
2101
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002102RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure) {
2103 HandleScope scope(isolate);
2104 ASSERT(args.length() == 3);
2105 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002106 Handle<Object> receiver = args.at<Object>(0);
2107 Handle<String> key = args.at<String>(1);
2108 ic.UpdateState(receiver, key);
2109 return ic.Store(receiver, key, args.at<Object>(2));
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002110}
2111
2112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002113RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002114 SealHandleScope shs(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00002115
2116 ASSERT(args.length() == 2);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002117 JSArray* receiver = JSArray::cast(args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00002118 Object* len = args[1];
2119
lrn@chromium.org303ada72010-10-27 09:33:13 +00002120 // The generated code should filter out non-Smis before we get here.
2121 ASSERT(len->IsSmi());
2122
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002123#ifdef DEBUG
2124 // The length property has to be a writable callback property.
2125 LookupResult debug_lookup(isolate);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002126 receiver->LocalLookup(isolate->heap()->length_string(), &debug_lookup);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002127 ASSERT(debug_lookup.IsPropertyCallbacks() && !debug_lookup.IsReadOnly());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002128#endif
2129
lrn@chromium.org303ada72010-10-27 09:33:13 +00002130 Object* result;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002131 MaybeObject* maybe_result = receiver->SetElementsLength(len);
2132 if (!maybe_result->To(&result)) return maybe_result;
2133
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002134 return len;
ager@chromium.org5c838252010-02-19 08:53:10 +00002135}
2136
2137
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002138// Extend storage is called in a store inline cache when
2139// it is necessary to extend the properties array of a
2140// JSObject.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002141RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002142 SealHandleScope shs(isolate);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002143 ASSERT(args.length() == 3);
2144
2145 // Convert the parameters
2146 JSObject* object = JSObject::cast(args[0]);
2147 Map* transition = Map::cast(args[1]);
2148 Object* value = args[2];
2149
2150 // Check the object has run out out property space.
2151 ASSERT(object->HasFastProperties());
2152 ASSERT(object->map()->unused_property_fields() == 0);
2153
2154 // Expand the properties array.
2155 FixedArray* old_storage = object->properties();
2156 int new_unused = transition->unused_property_fields();
2157 int new_size = old_storage->length() + new_unused + 1;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002158 Object* result;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002159 MaybeObject* maybe_result = old_storage->CopySize(new_size);
2160 if (!maybe_result->ToObject(&result)) return maybe_result;
2161
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002162 FixedArray* new_storage = FixedArray::cast(result);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002163
2164 Object* to_store = value;
2165
2166 if (FLAG_track_double_fields) {
2167 DescriptorArray* descriptors = transition->instance_descriptors();
2168 PropertyDetails details = descriptors->GetDetails(transition->LastAdded());
2169 if (details.representation().IsDouble()) {
2170 MaybeObject* maybe_storage =
2171 isolate->heap()->AllocateHeapNumber(value->Number());
2172 if (!maybe_storage->To(&to_store)) return maybe_storage;
2173 }
2174 }
2175
2176 new_storage->set(old_storage->length(), to_store);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002177
ager@chromium.org32912102009-01-16 10:38:43 +00002178 // Set the new property value and do the map transition.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002179 object->set_properties(new_storage);
2180 object->set_map(transition);
2181
2182 // Return the stored value.
2183 return value;
2184}
2185
2186
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002187// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002188RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002189 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190 ASSERT(args.length() == 3);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002191 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002192 Handle<Object> receiver = args.at<Object>(0);
2193 Handle<Object> key = args.at<Object>(1);
2194 ic.UpdateState(receiver, key);
2195 return ic.Store(receiver, key, args.at<Object>(2), MISS);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002196}
2197
2198
2199RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure) {
2200 HandleScope scope(isolate);
2201 ASSERT(args.length() == 3);
2202 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002203 Handle<Object> receiver = args.at<Object>(0);
2204 Handle<Object> key = args.at<Object>(1);
2205 ic.UpdateState(receiver, key);
2206 return ic.Store(receiver, key, args.at<Object>(2), MISS);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002207}
2208
2209
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002210RUNTIME_FUNCTION(MaybeObject*, StoreIC_Slow) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002211 HandleScope scope(isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002212 ASSERT(args.length() == 3);
2213 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002214 Handle<Object> object = args.at<Object>(0);
2215 Handle<Object> key = args.at<Object>(1);
2216 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002217 StrictModeFlag strict_mode = ic.strict_mode();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002218 return Runtime::SetObjectProperty(isolate,
2219 object,
2220 key,
2221 value,
2222 NONE,
2223 strict_mode);
2224}
2225
2226
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002227RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002228 HandleScope scope(isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002229 ASSERT(args.length() == 3);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002230 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002231 Handle<Object> object = args.at<Object>(0);
2232 Handle<Object> key = args.at<Object>(1);
2233 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002234 StrictModeFlag strict_mode = ic.strict_mode();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002235 return Runtime::SetObjectProperty(isolate,
2236 object,
2237 key,
2238 value,
2239 NONE,
2240 strict_mode);
2241}
2242
2243
2244RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002245 HandleScope scope(isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002246 ASSERT(args.length() == 3);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002247 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002248 Handle<Object> receiver = args.at<Object>(0);
2249 Handle<Object> key = args.at<Object>(1);
2250 ic.UpdateState(receiver, key);
2251 return ic.Store(receiver, key, args.at<Object>(2), MISS_FORCE_GENERIC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002252}
2253
2254
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00002255RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002256 HandleScope scope(isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00002257 ASSERT(args.length() == 4);
2258 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00002259 Handle<Object> value = args.at<Object>(0);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00002260 Handle<Map> map = args.at<Map>(1);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00002261 Handle<Object> key = args.at<Object>(2);
2262 Handle<Object> object = args.at<Object>(3);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002263 StrictModeFlag strict_mode = ic.strict_mode();
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00002264 if (object->IsJSObject()) {
2265 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2266 map->elements_kind());
2267 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00002268 return Runtime::SetObjectProperty(isolate,
2269 object,
2270 key,
2271 value,
2272 NONE,
2273 strict_mode);
2274}
2275
2276
danno@chromium.org40cb8782011-05-25 07:58:50 +00002277const char* BinaryOpIC::GetName(TypeInfo type_info) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002278 switch (type_info) {
2279 case UNINITIALIZED: return "Uninitialized";
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002280 case SMI: return "Smi";
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002281 case INT32: return "Int32";
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002282 case NUMBER: return "Number";
lrn@chromium.org7516f052011-03-30 08:52:27 +00002283 case ODDBALL: return "Oddball";
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002284 case STRING: return "String";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002285 case GENERIC: return "Generic";
2286 default: return "Invalid";
2287 }
2288}
2289
2290
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002291MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) {
2292 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
2293 BinaryOpStub stub(extra_ic_state);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002294
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002295 Handle<Type> left_type = stub.GetLeftType(isolate());
2296 Handle<Type> right_type = stub.GetRightType(isolate());
2297 bool smi_was_enabled = left_type->Maybe(Type::Smi()) &&
2298 right_type->Maybe(Type::Smi());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002299
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002300 Maybe<Handle<Object> > result = stub.Result(left, right, isolate());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002301
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002302#ifdef DEBUG
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002303 if (FLAG_trace_ic) {
2304 char buffer[100];
2305 NoAllocationStringAllocator allocator(buffer,
2306 static_cast<unsigned>(sizeof(buffer)));
2307 StringStream stream(&allocator);
2308 stream.Add("[");
2309 stub.PrintName(&stream);
2310
2311 stub.UpdateStatus(left, right, result);
2312
2313 stream.Add(" => ");
2314 stub.PrintState(&stream);
2315 stream.Add(" ");
2316 stream.OutputToStdOut();
2317 PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate())));
2318 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2319 PrintF("]\n");
2320 } else {
2321 stub.UpdateStatus(left, right, result);
2322 }
2323#else
2324 stub.UpdateStatus(left, right, result);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002325#endif
2326
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002327 Handle<Code> code = stub.GetCode(isolate());
2328 set_target(*code);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002329
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002330 left_type = stub.GetLeftType(isolate());
2331 right_type = stub.GetRightType(isolate());
2332 bool enable_smi = left_type->Maybe(Type::Smi()) &&
2333 right_type->Maybe(Type::Smi());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002334
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002335 if (!smi_was_enabled && enable_smi) {
2336 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2337 } else if (smi_was_enabled && !enable_smi) {
2338 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK);
2339 }
2340
2341 return result.has_value
2342 ? static_cast<MaybeObject*>(*result.value)
2343 : Failure::Exception();
2344}
2345
2346
2347RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002348 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002349 Handle<Object> left = args.at<Object>(0);
2350 Handle<Object> right = args.at<Object>(1);
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002351 BinaryOpIC ic(isolate);
2352 return ic.Transition(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002353}
2354
2355
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00002356Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002357 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002358 Code* code = NULL;
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00002359 CHECK(stub.FindCodeInCache(&code, isolate));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002360 return code;
2361}
2362
2363
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002364Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002365 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002366 return stub.GetCode(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002367}
2368
2369
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002370const char* CompareIC::GetStateName(State state) {
2371 switch (state) {
2372 case UNINITIALIZED: return "UNINITIALIZED";
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002373 case SMI: return "SMI";
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002374 case NUMBER: return "NUMBER";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002375 case INTERNALIZED_STRING: return "INTERNALIZED_STRING";
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002376 case STRING: return "STRING";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002377 case UNIQUE_NAME: return "UNIQUE_NAME";
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002378 case OBJECT: return "OBJECT";
2379 case KNOWN_OBJECT: return "KNOWN_OBJECT";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002380 case GENERIC: return "GENERIC";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002381 }
danno@chromium.org41728482013-06-12 22:31:22 +00002382 UNREACHABLE();
2383 return NULL;
2384}
2385
2386
2387Handle<Type> CompareIC::StateToType(
2388 Isolate* isolate,
2389 CompareIC::State state,
2390 Handle<Map> map) {
2391 switch (state) {
2392 case CompareIC::UNINITIALIZED:
2393 return handle(Type::None(), isolate);
2394 case CompareIC::SMI:
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002395 return handle(Type::Smi(), isolate);
danno@chromium.org41728482013-06-12 22:31:22 +00002396 case CompareIC::NUMBER:
2397 return handle(Type::Number(), isolate);
2398 case CompareIC::STRING:
2399 return handle(Type::String(), isolate);
2400 case CompareIC::INTERNALIZED_STRING:
2401 return handle(Type::InternalizedString(), isolate);
2402 case CompareIC::UNIQUE_NAME:
2403 return handle(Type::UniqueName(), isolate);
2404 case CompareIC::OBJECT:
2405 return handle(Type::Receiver(), isolate);
2406 case CompareIC::KNOWN_OBJECT:
2407 return handle(
2408 map.is_null() ? Type::Receiver() : Type::Class(map), isolate);
2409 case CompareIC::GENERIC:
2410 return handle(Type::Any(), isolate);
2411 }
2412 UNREACHABLE();
2413 return Handle<Type>();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002414}
2415
2416
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002417void CompareIC::StubInfoToType(int stub_minor_key,
2418 Handle<Type>* left_type,
2419 Handle<Type>* right_type,
2420 Handle<Type>* overall_type,
2421 Handle<Map> map,
2422 Isolate* isolate) {
2423 State left_state, right_state, handler_state;
2424 ICCompareStub::DecodeMinorKey(stub_minor_key, &left_state, &right_state,
2425 &handler_state, NULL);
2426 *left_type = StateToType(isolate, left_state);
2427 *right_type = StateToType(isolate, right_state);
2428 *overall_type = StateToType(isolate, handler_state, map);
2429}
2430
2431
2432CompareIC::State CompareIC::NewInputState(State old_state,
2433 Handle<Object> value) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002434 switch (old_state) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002435 case UNINITIALIZED:
2436 if (value->IsSmi()) return SMI;
2437 if (value->IsHeapNumber()) return NUMBER;
2438 if (value->IsInternalizedString()) return INTERNALIZED_STRING;
2439 if (value->IsString()) return STRING;
2440 if (value->IsSymbol()) return UNIQUE_NAME;
2441 if (value->IsJSObject()) return OBJECT;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002442 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002443 case SMI:
2444 if (value->IsSmi()) return SMI;
2445 if (value->IsHeapNumber()) return NUMBER;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002446 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002447 case NUMBER:
2448 if (value->IsNumber()) return NUMBER;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002449 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002450 case INTERNALIZED_STRING:
2451 if (value->IsInternalizedString()) return INTERNALIZED_STRING;
2452 if (value->IsString()) return STRING;
2453 if (value->IsSymbol()) return UNIQUE_NAME;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002454 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002455 case STRING:
2456 if (value->IsString()) return STRING;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002457 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002458 case UNIQUE_NAME:
2459 if (value->IsUniqueName()) return UNIQUE_NAME;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002460 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002461 case OBJECT:
2462 if (value->IsJSObject()) return OBJECT;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002463 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002464 case GENERIC:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002465 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002466 case KNOWN_OBJECT:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002467 UNREACHABLE();
2468 break;
2469 }
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002470 return GENERIC;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002471}
2472
2473
2474CompareIC::State CompareIC::TargetState(State old_state,
2475 State old_left,
2476 State old_right,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002477 bool has_inlined_smi_code,
2478 Handle<Object> x,
2479 Handle<Object> y) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002480 switch (old_state) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002481 case UNINITIALIZED:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002482 if (x->IsSmi() && y->IsSmi()) return SMI;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002483 if (x->IsNumber() && y->IsNumber()) return NUMBER;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002484 if (Token::IsOrderedRelationalCompareOp(op_)) {
2485 // Ordered comparisons treat undefined as NaN, so the
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002486 // NUMBER stub will do the right thing.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002487 if ((x->IsNumber() && y->IsUndefined()) ||
2488 (y->IsNumber() && x->IsUndefined())) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002489 return NUMBER;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002490 }
2491 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002492 if (x->IsInternalizedString() && y->IsInternalizedString()) {
2493 // We compare internalized strings as plain ones if we need to determine
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002494 // the order in a non-equality compare.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002495 return Token::IsEqualityOp(op_) ? INTERNALIZED_STRING : STRING;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002496 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002497 if (x->IsString() && y->IsString()) return STRING;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002498 if (!Token::IsEqualityOp(op_)) return GENERIC;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002499 if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002500 if (x->IsJSObject() && y->IsJSObject()) {
2501 if (Handle<JSObject>::cast(x)->map() ==
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002502 Handle<JSObject>::cast(y)->map()) {
2503 return KNOWN_OBJECT;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002504 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002505 return OBJECT;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002506 }
2507 }
2508 return GENERIC;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002509 case SMI:
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002510 return x->IsNumber() && y->IsNumber() ? NUMBER : GENERIC;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002511 case INTERNALIZED_STRING:
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002512 ASSERT(Token::IsEqualityOp(op_));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002513 if (x->IsString() && y->IsString()) return STRING;
2514 if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
2515 return GENERIC;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002516 case NUMBER:
2517 // If the failure was due to one side changing from smi to heap number,
2518 // then keep the state (if other changed at the same time, we will get
2519 // a second miss and then go to generic).
2520 if (old_left == SMI && x->IsHeapNumber()) return NUMBER;
2521 if (old_right == SMI && y->IsHeapNumber()) return NUMBER;
2522 return GENERIC;
2523 case KNOWN_OBJECT:
2524 ASSERT(Token::IsEqualityOp(op_));
2525 if (x->IsJSObject() && y->IsJSObject()) return OBJECT;
2526 return GENERIC;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002527 case STRING:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002528 case UNIQUE_NAME:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002529 case OBJECT:
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002530 case GENERIC:
2531 return GENERIC;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002532 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002533 UNREACHABLE();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002534 return GENERIC; // Make the compiler happy.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002535}
2536
2537
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002538void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002539 HandleScope scope(isolate());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002540 State previous_left, previous_right, previous_state;
2541 ICCompareStub::DecodeMinorKey(target()->stub_info(), &previous_left,
2542 &previous_right, &previous_state, NULL);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002543 State new_left = NewInputState(previous_left, x);
2544 State new_right = NewInputState(previous_right, y);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002545 State state = TargetState(previous_state, previous_left, previous_right,
2546 HasInlinedSmiCode(address()), x, y);
2547 ICCompareStub stub(op_, new_left, new_right, state);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002548 if (state == KNOWN_OBJECT) {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002549 stub.set_known_map(
2550 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate()));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002551 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002552 set_target(*stub.GetCode(isolate()));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002553
2554#ifdef DEBUG
2555 if (FLAG_trace_ic) {
2556 PrintF("[CompareIC in ");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002557 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002558 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
2559 GetStateName(previous_left),
2560 GetStateName(previous_right),
2561 GetStateName(previous_state),
2562 GetStateName(new_left),
2563 GetStateName(new_right),
2564 GetStateName(state),
2565 Token::Name(op_),
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002566 static_cast<void*>(*stub.GetCode(isolate())));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002567 }
2568#endif
2569
2570 // Activate inlined smi code.
2571 if (previous_state == UNINITIALIZED) {
2572 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2573 }
2574}
2575
2576
2577// Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002578RUNTIME_FUNCTION(Code*, CompareIC_Miss) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002579 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002580 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002581 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002582 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002583 return ic.raw_target();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002584}
2585
2586
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002587void CompareNilIC::Clear(Address address, Code* target) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002588 if (IsCleared(target)) return;
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002589 Code::ExtraICState state = target->extended_extra_ic_state();
2590
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002591 CompareNilICStub stub(state, HydrogenCodeStub::UNINITIALIZED);
danno@chromium.org41728482013-06-12 22:31:22 +00002592 stub.ClearState();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002593
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002594 Code* code = NULL;
2595 CHECK(stub.FindCodeInCache(&code, target->GetIsolate()));
2596
2597 SetTargetAtAddress(address, code);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002598}
2599
2600
ulan@chromium.org837a67e2013-06-11 15:39:48 +00002601MaybeObject* CompareNilIC::DoCompareNilSlow(NilValue nil,
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002602 Handle<Object> object) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002603 if (object->IsNull() || object->IsUndefined()) {
2604 return Smi::FromInt(true);
2605 }
2606 return Smi::FromInt(object->IsUndetectableObject());
2607}
2608
2609
2610MaybeObject* CompareNilIC::CompareNil(Handle<Object> object) {
2611 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
2612
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002613 CompareNilICStub stub(extra_ic_state);
2614
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002615 // Extract the current supported types from the patched IC and calculate what
2616 // types must be supported as a result of the miss.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002617 bool already_monomorphic = stub.IsMonomorphic();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002618
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002619 stub.UpdateStatus(object);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002620
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002621 NilValue nil = stub.GetNilValue();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002622
2623 // Find or create the specialized stub to support the new set of types.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002624 Handle<Code> code;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002625 if (stub.IsMonomorphic()) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002626 Handle<Map> monomorphic_map(already_monomorphic
2627 ? target()->FindFirstMap()
2628 : HeapObject::cast(*object)->map());
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002629 code = isolate()->stub_cache()->ComputeCompareNil(monomorphic_map, stub);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002630 } else {
2631 code = stub.GetCode(isolate());
2632 }
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002633 set_target(*code);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00002634 return DoCompareNilSlow(nil, object);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002635}
2636
2637
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002638RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss) {
2639 HandleScope scope(isolate);
2640 Handle<Object> object = args.at<Object>(0);
2641 CompareNilIC ic(isolate);
2642 return ic.CompareNil(object);
2643}
2644
2645
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002646RUNTIME_FUNCTION(MaybeObject*, Unreachable) {
2647 UNREACHABLE();
2648 CHECK(false);
2649 return isolate->heap()->undefined_value();
2650}
2651
2652
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002653Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) {
2654 switch (op) {
2655 default:
2656 UNREACHABLE();
2657 case Token::ADD:
2658 return Builtins::ADD;
2659 break;
2660 case Token::SUB:
2661 return Builtins::SUB;
2662 break;
2663 case Token::MUL:
2664 return Builtins::MUL;
2665 break;
2666 case Token::DIV:
2667 return Builtins::DIV;
2668 break;
2669 case Token::MOD:
2670 return Builtins::MOD;
2671 break;
2672 case Token::BIT_OR:
2673 return Builtins::BIT_OR;
2674 break;
2675 case Token::BIT_AND:
2676 return Builtins::BIT_AND;
2677 break;
2678 case Token::BIT_XOR:
2679 return Builtins::BIT_XOR;
2680 break;
2681 case Token::SAR:
2682 return Builtins::SAR;
2683 break;
2684 case Token::SHR:
2685 return Builtins::SHR;
2686 break;
2687 case Token::SHL:
2688 return Builtins::SHL;
2689 break;
2690 }
2691}
2692
2693
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002694MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object,
2695 Code::ExtraICState extra_ic_state) {
2696 ToBooleanStub stub(extra_ic_state);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002697 bool to_boolean_value = stub.UpdateStatus(object);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002698 Handle<Code> code = stub.GetCode(isolate());
2699 set_target(*code);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00002700 return Smi::FromInt(to_boolean_value ? 1 : 0);
2701}
2702
2703
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002704RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss) {
2705 ASSERT(args.length() == 1);
2706 HandleScope scope(isolate);
2707 Handle<Object> object = args.at<Object>(0);
2708 ToBooleanIC ic(isolate);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002709 Code::ExtraICState extra_ic_state = ic.target()->extended_extra_ic_state();
2710 return ic.ToBoolean(object, extra_ic_state);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00002711}
2712
2713
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002714static const Address IC_utilities[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002715#define ADDR(name) FUNCTION_ADDR(name),
2716 IC_UTIL_LIST(ADDR)
2717 NULL
2718#undef ADDR
2719};
2720
2721
2722Address IC::AddressFromUtilityId(IC::UtilityId id) {
2723 return IC_utilities[id];
2724}
2725
2726
2727} } // namespace v8::internal