blob: 2f7db26f2836f28e4af2b1d15e79ecb74635e9a4 [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
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000120IC::IC(FrameDepth depth, Isolate* isolate)
121 : isolate_(isolate),
122 target_set_(false) {
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000123 // To improve the performance of the (much used) IC code, we unfold a few
124 // levels of the stack frame iteration code. This yields a ~35% speedup when
125 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
126 const Address entry =
127 Isolate::c_entry_fp(isolate->thread_local_top());
128 Address* pc_address =
129 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
130 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
131 // If there's another JavaScript frame on the stack or a
132 // StubFailureTrampoline, we need to look one frame further down the stack to
133 // find the frame pointer and the return address stack slot.
134 if (depth == EXTRA_CALL_FRAME) {
135 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
136 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
137 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
138 }
139#ifdef DEBUG
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000140 StackFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000141 for (int i = 0; i < depth + 1; i++) it.Advance();
142 StackFrame* frame = it.frame();
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000143 ASSERT(fp == frame->fp() && pc_address == frame->pc_address());
144#endif
145 fp_ = fp;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000146 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000147 target_ = handle(raw_target(), isolate);
148 state_ = target_->ic_state();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149}
150
151
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000152#ifdef ENABLE_DEBUGGER_SUPPORT
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000153Address IC::OriginalCodeAddress() const {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000154 HandleScope scope(isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155 // Compute the JavaScript frame for the frame pointer of this IC
156 // structure. We need this to be able to find the function
157 // corresponding to the frame.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000158 StackFrameIterator it(isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159 while (it.frame()->fp() != this->fp()) it.Advance();
160 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
161 // Find the function on the stack and both the active code for the
162 // function and the original code.
danno@chromium.org169691d2013-07-15 08:01:13 +0000163 JSFunction* function = frame->function();
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000164 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000165 Code* code = shared->code();
166 ASSERT(Debug::HasDebugInfo(shared));
167 Code* original_code = Debug::GetDebugInfo(shared)->original_code();
168 ASSERT(original_code->IsCode());
169 // Get the address of the call site in the active code. This is the
170 // place where the call to DebugBreakXXX is and where the IC
171 // normally would be.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000172 Address addr = Assembler::target_address_from_return_address(pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173 // Return the address in the original code. This is the place where
ager@chromium.org32912102009-01-16 10:38:43 +0000174 // the call which has been overwritten by the DebugBreakXXX resides
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000175 // and the place where the inline cache system should look.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000176 intptr_t delta =
177 original_code->instruction_start() - code->instruction_start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000178 return addr + delta;
179}
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000180#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000181
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000182
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000183static bool HasInterceptorGetter(JSObject* object) {
184 return !object->GetNamedInterceptor()->getter()->IsUndefined();
185}
186
187
188static bool HasInterceptorSetter(JSObject* object) {
189 return !object->GetNamedInterceptor()->setter()->IsUndefined();
190}
191
192
193static void LookupForRead(Handle<Object> object,
194 Handle<String> name,
195 LookupResult* lookup) {
196 // Skip all the objects with named interceptors, but
197 // without actual getter.
198 while (true) {
199 object->Lookup(*name, lookup);
200 // Besides normal conditions (property not found or it's not
201 // an interceptor), bail out if lookup is not cacheable: we won't
202 // be able to IC it anyway and regular lookup should work fine.
203 if (!lookup->IsInterceptor() || !lookup->IsCacheable()) {
204 return;
205 }
206
207 Handle<JSObject> holder(lookup->holder(), lookup->isolate());
208 if (HasInterceptorGetter(*holder)) {
209 return;
210 }
211
212 holder->LocalLookupRealNamedProperty(*name, lookup);
213 if (lookup->IsFound()) {
214 ASSERT(!lookup->IsInterceptor());
215 return;
216 }
217
218 Handle<Object> proto(holder->GetPrototype(), lookup->isolate());
219 if (proto->IsNull()) {
220 ASSERT(!lookup->IsFound());
221 return;
222 }
223
224 object = proto;
225 }
226}
227
228
229bool CallIC::TryUpdateExtraICState(LookupResult* lookup,
230 Handle<Object> object) {
231 if (!lookup->IsConstantFunction()) return false;
232 JSFunction* function = lookup->GetConstantFunction();
233 if (!function->shared()->HasBuiltinFunctionId()) return false;
234
235 // Fetch the arguments passed to the called function.
236 const int argc = target()->arguments_count();
237 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top());
238 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
239 Arguments args(argc + 1,
240 &Memory::Object_at(fp +
241 StandardFrameConstants::kCallerSPOffset +
242 argc * kPointerSize));
243 switch (function->shared()->builtin_function_id()) {
244 case kStringCharCodeAt:
245 case kStringCharAt:
246 if (object->IsString()) {
247 String* string = String::cast(*object);
248 // Check there's the right string value or wrapper in the receiver slot.
249 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value());
250 // If we're in the default (fastest) state and the index is
251 // out of bounds, update the state to record this fact.
252 if (StringStubState::decode(extra_ic_state()) == DEFAULT_STRING_STUB &&
253 argc >= 1 && args[1]->IsNumber()) {
254 double index = DoubleToInteger(args.number_at(1));
255 if (index < 0 || index >= string->length()) {
256 extra_ic_state_ =
257 StringStubState::update(extra_ic_state(),
258 STRING_INDEX_OUT_OF_BOUNDS);
259 return true;
260 }
261 }
262 }
263 break;
264 default:
265 return false;
266 }
267 return false;
268}
269
270
271bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
272 Handle<String> name) {
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
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000769 if (state() == UNINITIALIZED) {
770 set_target(*pre_monomorphic_stub());
771 TRACE_IC("CallIC", name);
772 return;
773 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000774
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000775 Handle<Code> code = ComputeMonomorphicStub(lookup, object, name);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000776 // If there's no appropriate stub we simply avoid updating the caches.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000777 // TODO(verwaest): Install a slow fallback in this case to avoid not learning,
778 // and deopting Crankshaft code.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000779 if (code.is_null()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000780
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000781 Handle<JSObject> cache_object = object->IsJSObject()
782 ? Handle<JSObject>::cast(object)
783 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())),
784 isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000785
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000786 PatchCache(cache_object, name, code);
787 TRACE_IC("CallIC", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000788}
789
790
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000791MaybeObject* KeyedCallIC::LoadFunction(Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000792 Handle<Object> key) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000793 if (key->IsInternalizedString()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000794 return CallICBase::LoadFunction(object, Handle<String>::cast(key));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000795 }
796
797 if (object->IsUndefined() || object->IsNull()) {
798 return TypeError("non_object_property_call", object, key);
799 }
800
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000801 bool use_ic = MigrateDeprecated(object)
802 ? false : FLAG_use_ic && !object->IsAccessCheckNeeded();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000803
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000804 if (use_ic && state() != MEGAMORPHIC) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000805 ASSERT(!object->IsJSGlobalProxy());
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000806 int argc = target()->arguments_count();
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000807 Handle<Code> stub;
808
809 // Use the KeyedArrayCallStub if the call is of the form array[smi](...),
810 // where array is an instance of one of the initial array maps (without
811 // extra named properties).
812 // TODO(verwaest): Also support keyed calls on instances of other maps.
813 if (object->IsJSArray() && key->IsSmi()) {
814 Handle<JSArray> array = Handle<JSArray>::cast(object);
815 ElementsKind kind = array->map()->elements_kind();
816 if (IsFastObjectElementsKind(kind) &&
817 array->map() == isolate()->get_initial_js_array_map(kind)) {
818 KeyedArrayCallStub stub_gen(IsHoleyElementsKind(kind), argc);
819 stub = stub_gen.GetCode(isolate());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000820 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000821 }
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000822
823 if (stub.is_null()) {
824 stub = isolate()->stub_cache()->ComputeCallMegamorphic(
825 argc, Code::KEYED_CALL_IC, Code::kNoExtraICState);
826 if (object->IsJSObject()) {
827 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
828 if (receiver->elements()->map() ==
829 isolate()->heap()->non_strict_arguments_elements_map()) {
830 stub = isolate()->stub_cache()->ComputeCallArguments(argc);
831 }
832 }
833 ASSERT(!stub.is_null());
834 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000835 set_target(*stub);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000836 TRACE_IC("CallIC", key);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000837 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000838
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000839 Handle<Object> result = GetProperty(isolate(), object, key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000840 RETURN_IF_EMPTY_HANDLE(isolate(), result);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000841
842 // Make receiver an object if the callee requires it. Strict mode or builtin
843 // functions do not wrap the receiver, non-strict functions and objects
844 // called as functions do.
845 ReceiverToObjectIfRequired(result, object);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000846 if (result->IsJSFunction()) return *result;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000847
848 result = TryCallAsFunction(result);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000849 if (result->IsJSFunction()) return *result;
850
851 return TypeError("property_not_function", object, key);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000852}
853
854
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000855MaybeObject* LoadIC::Load(Handle<Object> object,
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000856 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000857 // If the object is undefined or null it's illegal to try to get any
858 // of its properties; throw a TypeError in that case.
859 if (object->IsUndefined() || object->IsNull()) {
860 return TypeError("non_object_property_load", object, name);
861 }
862
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000863 if (FLAG_use_ic) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000864 // Use specialized code for getting the length of strings and
865 // string wrapper objects. The length property of string wrapper
866 // objects is read-only and therefore always returns the length of
867 // the underlying string value. See ECMA-262 15.5.5.1.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000868 if (object->IsStringWrapper() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000869 name->Equals(isolate()->heap()->length_string())) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000870 Handle<Code> stub;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000871 if (state() == UNINITIALIZED) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000872 stub = pre_monomorphic_stub();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000873 } else if (state() == PREMONOMORPHIC || state() == MONOMORPHIC) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000874 StringLengthStub string_length_stub(kind());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000875 stub = string_length_stub.GetCode(isolate());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000876 } else if (state() != MEGAMORPHIC) {
877 ASSERT(state() != GENERIC);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000878 stub = megamorphic_stub();
879 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000880 if (!stub.is_null()) {
881 set_target(*stub);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000882#ifdef DEBUG
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000883 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /stringwrapper]\n");
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000884#endif
ager@chromium.org378b34e2011-01-28 08:04:38 +0000885 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000886 // Get the string if we have a string wrapper object.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000887 String* string = String::cast(JSValue::cast(*object)->value());
888 return Smi::FromInt(string->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889 }
890
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891 // Use specialized code for getting prototype of functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000892 if (object->IsJSFunction() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000893 name->Equals(isolate()->heap()->prototype_string()) &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000894 Handle<JSFunction>::cast(object)->should_have_prototype()) {
895 Handle<Code> stub;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000896 if (state() == UNINITIALIZED) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000897 stub = pre_monomorphic_stub();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000898 } else if (state() == PREMONOMORPHIC) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000899 FunctionPrototypeStub function_prototype_stub(kind());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000900 stub = function_prototype_stub.GetCode(isolate());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000901 } else if (state() != MEGAMORPHIC) {
902 ASSERT(state() != GENERIC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000903 stub = megamorphic_stub();
904 }
905 if (!stub.is_null()) {
906 set_target(*stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000907#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000908 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000909#endif
ager@chromium.org378b34e2011-01-28 08:04:38 +0000910 }
rossberg@chromium.orgebeba022013-08-19 09:36:44 +0000911 return *Accessors::FunctionGetPrototype(Handle<JSFunction>::cast(object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000912 }
913 }
914
915 // Check if the name is trivially convertible to an index and get
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000916 // the element or char if so.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000917 uint32_t index;
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000918 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
919 // Rewrite to the generic keyed load stub.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000920 if (FLAG_use_ic) set_target(*generic_stub());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000921 return Runtime::GetElementOrCharAtOrFail(isolate(), object, index);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000922 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000924 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000925
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 // Named lookup in the object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000927 LookupResult lookup(isolate());
928 LookupForRead(object, name, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000929
ager@chromium.org5c838252010-02-19 08:53:10 +0000930 // If we did not find a property, check if we need to throw an exception.
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000931 if (!lookup.IsFound()) {
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +0000932 if (IsUndeclaredGlobal(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933 return ReferenceError("not_defined", name);
934 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000935 LOG(isolate(), SuspectReadEvent(*name, *object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000936 }
937
938 // Update inline cache and stub cache.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000939 if (use_ic) UpdateCaches(&lookup, object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000940
941 PropertyAttributes attr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942 // Get the property.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000943 Handle<Object> result =
944 Object::GetProperty(object, object, &lookup, name, &attr);
945 RETURN_IF_EMPTY_HANDLE(isolate(), result);
946 // If the property is not present, check if we need to throw an
947 // exception.
948 if ((lookup.IsInterceptor() || lookup.IsHandler()) &&
949 attr == ABSENT && IsUndeclaredGlobal(object)) {
950 return ReferenceError("not_defined", name);
951 }
952 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000953}
954
955
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000956static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
957 Handle<Map> new_receiver_map) {
958 ASSERT(!new_receiver_map.is_null());
959 for (int current = 0; current < receiver_maps->length(); ++current) {
960 if (!receiver_maps->at(current).is_null() &&
961 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
962 return false;
963 }
964 }
965 receiver_maps->Add(new_receiver_map);
966 return true;
967}
968
969
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000970bool IC::UpdatePolymorphicIC(Handle<Object> receiver,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000971 Handle<String> name,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000972 Handle<Code> code) {
973 if (!code->is_handler()) return false;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000974 MapHandleList receiver_maps;
975 CodeHandleList handlers;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000976
danno@chromium.orgf005df62013-04-30 16:36:45 +0000977 int number_of_valid_maps;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000978 int handler_to_overwrite = -1;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000979 Handle<Map> new_receiver_map(receiver->GetMarkerMap(isolate()));
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000980
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000981 target()->FindAllMaps(&receiver_maps);
982 int number_of_maps = receiver_maps.length();
983 number_of_valid_maps = number_of_maps;
984
985 for (int i = 0; i < number_of_maps; i++) {
986 Handle<Map> map = receiver_maps.at(i);
987 // Filter out deprecated maps to ensure its instances get migrated.
988 if (map->is_deprecated()) {
989 number_of_valid_maps--;
990 // If the receiver map is already in the polymorphic IC, this indicates
991 // there was a prototoype chain failure. In that case, just overwrite the
992 // handler.
993 } else if (map.is_identical_to(new_receiver_map)) {
994 number_of_valid_maps--;
995 handler_to_overwrite = i;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000996 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000997 }
danno@chromium.orgf005df62013-04-30 16:36:45 +0000998
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000999 if (number_of_valid_maps >= 4) return false;
1000 if (number_of_maps == 0) return false;
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +00001001
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001002 if (!target()->FindHandlers(&handlers, receiver_maps.length())) {
1003 return false;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001004 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001005
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001006 number_of_valid_maps++;
1007 if (handler_to_overwrite >= 0) {
1008 handlers.Set(handler_to_overwrite, code);
1009 } else {
1010 receiver_maps.Add(new_receiver_map);
1011 handlers.Add(code);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001012 }
1013
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001014 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
1015 &receiver_maps, &handlers, number_of_valid_maps, name, strict_mode());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001016 set_target(*ic);
1017 return true;
1018}
1019
1020
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001021void IC::UpdateMonomorphicIC(Handle<Object> receiver,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001022 Handle<Code> handler,
1023 Handle<String> name) {
1024 if (!handler->is_handler()) return set_target(*handler);
1025 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001026 name, receiver, handler, strict_mode());
danno@chromium.orgbee51992013-07-10 14:57:15 +00001027 set_target(*ic);
1028}
1029
1030
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001031void IC::CopyICToMegamorphicCache(Handle<String> name) {
1032 MapHandleList receiver_maps;
1033 CodeHandleList handlers;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001034 target()->FindAllMaps(&receiver_maps);
1035 if (!target()->FindHandlers(&handlers, receiver_maps.length())) return;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001036 for (int i = 0; i < receiver_maps.length(); i++) {
1037 UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i));
1038 }
1039}
1040
1041
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001042bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001043 Map* current_map = target()->FindFirstMap();
1044 ElementsKind receiver_elements_kind = receiver_map->elements_kind();
1045 bool more_general_transition =
1046 IsMoreGeneralElementsKindTransition(
1047 current_map->elements_kind(), receiver_elements_kind);
1048 Map* transitioned_map = more_general_transition
1049 ? current_map->LookupElementsTransitionMap(receiver_elements_kind)
1050 : NULL;
1051
1052 return transitioned_map == receiver_map;
1053}
1054
1055
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001056void IC::PatchCache(Handle<Object> object,
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001057 Handle<String> name,
1058 Handle<Code> code) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001059 switch (state()) {
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001060 case UNINITIALIZED:
1061 case PREMONOMORPHIC:
1062 case MONOMORPHIC_PROTOTYPE_FAILURE:
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001063 UpdateMonomorphicIC(object, code, name);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001064 break;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001065 case MONOMORPHIC: {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001066 // For now, call stubs are allowed to rewrite to the same stub. This
1067 // happens e.g., when the field does not contain a function.
1068 ASSERT(target()->is_call_stub() ||
1069 target()->is_keyed_call_stub() ||
1070 !target().is_identical_to(code));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001071 Code* old_handler = target()->FindFirstHandler();
1072 if (old_handler == *code &&
1073 IsTransitionedMapOfMonomorphicTarget(
1074 object->GetMarkerMap(isolate()))) {
1075 UpdateMonomorphicIC(object, code, name);
1076 break;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001077 }
1078 // Fall through.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001079 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001080 case POLYMORPHIC:
1081 if (!target()->is_keyed_stub()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001082 if (UpdatePolymorphicIC(object, name, code)) break;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001083 CopyICToMegamorphicCache(name);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001084 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001085 set_target(*megamorphic_stub());
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001086 // Fall through.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001087 case MEGAMORPHIC:
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001088 UpdateMegamorphicCache(object->GetMarkerMap(isolate()), *name, *code);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001089 break;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001090 case DEBUG_STUB:
1091 break;
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001092 case GENERIC:
1093 UNREACHABLE();
1094 break;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001095 }
1096}
1097
1098
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001099Handle<Code> LoadIC::SimpleFieldLoad(int offset,
1100 bool inobject,
1101 Representation representation) {
1102 if (kind() == Code::LOAD_IC) {
1103 LoadFieldStub stub(inobject, offset, representation);
1104 return stub.GetCode(isolate());
1105 } else {
1106 KeyedLoadFieldStub stub(inobject, offset, representation);
1107 return stub.GetCode(isolate());
1108 }
1109}
1110
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001111
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001112void LoadIC::UpdateCaches(LookupResult* lookup,
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001113 Handle<Object> object,
1114 Handle<String> name) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001115 if (state() == UNINITIALIZED) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001116 // This is the first time we execute this inline cache.
1117 // Set the target to the pre monomorphic stub to delay
1118 // setting the monomorphic state.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001119 set_target(*pre_monomorphic_stub());
1120 TRACE_IC("LoadIC", name);
1121 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001122 }
1123
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001124 Handle<Code> code;
1125 if (!lookup->IsCacheable()) {
1126 // Bail out if the result is not cacheable.
1127 code = slow_stub();
1128 } else if (!lookup->IsProperty()) {
1129 if (kind() == Code::LOAD_IC) {
1130 code = isolate()->stub_cache()->ComputeLoadNonexistent(name, object);
1131 } else {
1132 code = slow_stub();
1133 }
1134 } else {
1135 code = ComputeHandler(lookup, object, name);
1136 }
1137
1138 PatchCache(object, name, code);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001139 TRACE_IC("LoadIC", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001140}
1141
1142
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001143void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001144 // Cache code holding map should be consistent with
1145 // GenerateMonomorphicCacheProbe.
1146 isolate()->stub_cache()->Set(name, map, code);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001147}
1148
1149
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001150Handle<Code> IC::ComputeHandler(LookupResult* lookup,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001151 Handle<Object> object,
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001152 Handle<String> name,
1153 Handle<Object> value) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001154 InlineCacheHolderFlag cache_holder = GetCodeCacheForObject(*object);
1155 Handle<HeapObject> stub_holder(GetCodeCacheHolder(
1156 isolate(), *object, cache_holder));
1157
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001158 Handle<Code> code = isolate()->stub_cache()->FindHandler(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001159 name, stub_holder, kind(), cache_holder, strict_mode());
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001160 if (!code.is_null()) return code;
1161
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001162 code = CompileHandler(lookup, object, name, value, cache_holder);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001163 ASSERT(code->is_handler());
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001164
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001165 if (code->type() != Code::NORMAL) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001166 HeapObject::UpdateMapCodeCache(stub_holder, name, code);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001167 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001168
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001169 return code;
1170}
1171
1172
1173Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001174 Handle<Object> object,
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001175 Handle<String> name,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001176 Handle<Object> unused,
1177 InlineCacheHolderFlag cache_holder) {
1178 if (object->IsString() && name->Equals(isolate()->heap()->length_string())) {
1179 int length_index = String::kLengthOffset / kPointerSize;
1180 return SimpleFieldLoad(length_index);
1181 }
1182
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001183 Handle<JSObject> holder(lookup->holder());
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001184 LoadStubCompiler compiler(isolate(), cache_holder, kind());
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001185
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001186 switch (lookup->type()) {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001187 case FIELD: {
1188 PropertyIndex field = lookup->GetFieldIndex();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001189 if (object.is_identical_to(holder)) {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001190 return SimpleFieldLoad(field.translate(holder),
1191 field.is_inobject(holder),
1192 lookup->representation());
1193 }
1194 return compiler.CompileLoadField(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001195 object, holder, name, field, lookup->representation());
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001196 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001197 case CONSTANT: {
1198 Handle<Object> constant(lookup->GetConstant(), isolate());
1199 // TODO(2803): Don't compute a stub for cons strings because they cannot
1200 // be embedded into code.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001201 if (constant->IsConsString()) break;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001202 return compiler.CompileLoadConstant(object, holder, name, constant);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001203 }
1204 case NORMAL:
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001205 if (kind() != Code::LOAD_IC) break;
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001206 if (holder->IsGlobalObject()) {
1207 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001208 Handle<PropertyCell> cell(
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001209 global->GetPropertyCell(lookup), isolate());
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001210 Handle<Code> code = compiler.CompileLoadGlobal(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001211 object, global, cell, name, lookup->IsDontDelete());
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001212 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001213 Handle<HeapObject> stub_holder(GetCodeCacheHolder(
1214 isolate(), *object, cache_holder));
1215 HeapObject::UpdateMapCodeCache(stub_holder, name, code);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001216 return code;
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001217 }
1218 // There is only one shared stub for loading normalized
1219 // properties. It does not traverse the prototype chain, so the
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001220 // property must be found in the object for the stub to be
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001221 // applicable.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001222 if (!object.is_identical_to(holder)) break;
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001223 return isolate()->builtins()->LoadIC_Normal();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001224 case CALLBACKS: {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001225 // Use simple field loads for some well-known callback properties.
1226 int object_offset;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001227 if (object->IsJSObject()) {
1228 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
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());
1235 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001236 }
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00001237
1238 Handle<Object> callback(lookup->GetCallbackObject(), isolate());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001239 if (callback->IsExecutableAccessorInfo()) {
1240 Handle<ExecutableAccessorInfo> info =
1241 Handle<ExecutableAccessorInfo>::cast(callback);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001242 if (v8::ToCData<Address>(info->getter()) == 0) break;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001243 if (!info->IsCompatibleReceiver(*object)) break;
1244 return compiler.CompileLoadCallback(object, holder, name, info);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001245 } else if (callback->IsAccessorPair()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001246 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(),
1247 isolate());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001248 if (!getter->IsJSFunction()) break;
1249 if (holder->IsGlobalObject()) break;
1250 if (!holder->HasFastProperties()) break;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001251 Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001252 if (!object->IsJSObject() &&
1253 !function->IsBuiltin() &&
1254 function->shared()->is_classic_mode()) {
1255 // Calling non-strict non-builtins with a value as the receiver
1256 // requires boxing.
1257 break;
1258 }
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001259 CallOptimization call_optimization(function);
1260 if (call_optimization.is_simple_api_call() &&
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001261 call_optimization.IsCompatibleReceiver(*object)) {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001262 return compiler.CompileLoadCallback(
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001263 object, holder, name, call_optimization);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00001264 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001265 return compiler.CompileLoadViaGetter(object, holder, name, function);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001266 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001267 // TODO(dcarney): Handle correctly.
1268 if (callback->IsDeclaredAccessorInfo()) break;
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001269 ASSERT(callback->IsForeign());
1270 // No IC support for old-style native accessors.
1271 break;
1272 }
1273 case INTERCEPTOR:
1274 ASSERT(HasInterceptorGetter(*holder));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001275 return compiler.CompileLoadInterceptor(object, holder, name);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001276 default:
1277 break;
1278 }
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001279
1280 return slow_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001281}
1282
1283
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001284static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1285 // This helper implements a few common fast cases for converting
1286 // non-smi keys of keyed loads/stores to a smi or a string.
1287 if (key->IsHeapNumber()) {
1288 double value = Handle<HeapNumber>::cast(key)->value();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001289 if (std::isnan(value)) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001290 key = isolate->factory()->nan_string();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001291 } else {
1292 int int_value = FastD2I(value);
1293 if (value == int_value && Smi::IsValid(int_value)) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001294 key = Handle<Smi>(Smi::FromInt(int_value), isolate);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001295 }
1296 }
1297 } else if (key->IsUndefined()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001298 key = isolate->factory()->undefined_string();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001299 }
1300 return key;
1301}
1302
1303
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001304Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001305 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1306 // via megamorphic stubs, since they don't have a map in their relocation info
1307 // and so the stubs can't be harvested for the object needed for a map check.
1308 if (target()->type() != Code::NORMAL) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001309 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type");
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001310 return generic_stub();
1311 }
1312
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001313 Handle<Map> receiver_map(receiver->map(), isolate());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001314 MapHandleList target_receiver_maps;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001315 if (state() == UNINITIALIZED || state() == PREMONOMORPHIC) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001316 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
1317 // yet will do so and stay there.
1318 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1319 }
1320
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001321 if (target().is_identical_to(string_stub())) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001322 target_receiver_maps.Add(isolate()->factory()->string_map());
1323 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001324 target()->FindAllMaps(&target_receiver_maps);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001325 if (target_receiver_maps.length() == 0) {
1326 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1327 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001328 }
1329
1330 // The first time a receiver is seen that is a transitioned version of the
1331 // previous monomorphic receiver type, assume the new ElementsKind is the
1332 // monomorphic type. This benefits global arrays that only transition
1333 // once, and all call sites accessing them are faster if they remain
1334 // monomorphic. If this optimistic assumption is not true, the IC will
1335 // miss again and it will become polymorphic and support both the
1336 // untransitioned and transitioned maps.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001337 if (state() == MONOMORPHIC &&
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001338 IsMoreGeneralElementsKindTransition(
1339 target_receiver_maps.at(0)->elements_kind(),
1340 receiver->GetElementsKind())) {
1341 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1342 }
1343
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001344 ASSERT(state() != GENERIC);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001345
1346 // Determine the list of receiver maps that this call site has seen,
1347 // adding the map that was just encountered.
1348 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1349 // If the miss wasn't due to an unseen map, a polymorphic stub
1350 // won't help, use the generic stub.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001351 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice");
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001352 return generic_stub();
1353 }
1354
1355 // If the maximum number of receiver maps has been exceeded, use the generic
1356 // version of the IC.
1357 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001358 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded");
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001359 return generic_stub();
1360 }
1361
1362 return isolate()->stub_cache()->ComputeLoadElementPolymorphic(
1363 &target_receiver_maps);
1364}
1365
1366
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001367MaybeObject* KeyedLoadIC::LoadForceGeneric(Handle<Object> object,
1368 Handle<Object> key) {
1369 set_target(*generic_stub());
1370 return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
1371}
1372
1373
1374MaybeObject* KeyedLoadIC::Load(Handle<Object> object, Handle<Object> key) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001375 if (MigrateDeprecated(object)) {
1376 return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
1377 }
1378
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00001379 MaybeObject* maybe_object = NULL;
1380 Handle<Code> stub = generic_stub();
1381
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001382 // Check for values that can be converted into an internalized string directly
1383 // or is representable as a smi.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001384 key = TryConvertKey(key, isolate());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001385
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001386 if (key->IsInternalizedString()) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00001387 maybe_object = LoadIC::Load(object, Handle<String>::cast(key));
1388 if (maybe_object->IsFailure()) return maybe_object;
1389 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001390 ASSERT(!object->IsJSGlobalProxy());
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001391 if (object->IsString() && key->IsNumber()) {
1392 if (state() == UNINITIALIZED) stub = string_stub();
1393 } else if (object->IsJSObject()) {
1394 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1395 if (receiver->elements()->map() ==
1396 isolate()->heap()->non_strict_arguments_elements_map()) {
1397 stub = non_strict_arguments_stub();
1398 } else if (receiver->HasIndexedInterceptor()) {
1399 stub = indexed_interceptor_stub();
1400 } else if (!key->ToSmi()->IsFailure() &&
1401 (!target().is_identical_to(non_strict_arguments_stub()))) {
1402 stub = LoadElementStub(receiver);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001403 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001404 }
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00001405 }
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001406
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00001407 if (!is_target_set()) {
1408 if (*stub == *generic_stub()) {
1409 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
1410 }
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001411 ASSERT(!stub.is_null());
1412 set_target(*stub);
1413 TRACE_IC("LoadIC", key);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001414 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001415
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00001416 if (maybe_object != NULL) return maybe_object;
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00001417 return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418}
1419
1420
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001421static bool LookupForWrite(Handle<JSObject> receiver,
1422 Handle<String> name,
danno@chromium.orgf005df62013-04-30 16:36:45 +00001423 Handle<Object> value,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001424 LookupResult* lookup,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001425 IC* ic) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001426 Handle<JSObject> holder = receiver;
1427 receiver->Lookup(*name, lookup);
1428 if (lookup->IsFound()) {
1429 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
1430
1431 if (lookup->holder() == *receiver) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001432 if (lookup->IsInterceptor() && !HasInterceptorSetter(*receiver)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001433 receiver->LocalLookupRealNamedProperty(*name, lookup);
1434 return lookup->IsFound() &&
1435 !lookup->IsReadOnly() &&
danno@chromium.orgf005df62013-04-30 16:36:45 +00001436 lookup->CanHoldValue(value) &&
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001437 lookup->IsCacheable();
1438 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001439 return lookup->CanHoldValue(value);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001440 }
1441
1442 if (lookup->IsPropertyCallbacks()) return true;
1443
1444 // Currently normal holders in the prototype chain are not supported. They
1445 // would require a runtime positive lookup and verification that the details
1446 // have not changed.
1447 if (lookup->IsInterceptor() || lookup->IsNormal()) return false;
1448 holder = Handle<JSObject>(lookup->holder(), lookup->isolate());
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001449 }
1450
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001451 // While normally LookupTransition gets passed the receiver, in this case we
1452 // pass the holder of the property that we overwrite. This keeps the holder in
1453 // the LookupResult intact so we can later use it to generate a prototype
1454 // chain check. This avoids a double lookup, but requires us to pass in the
1455 // receiver when trying to fetch extra information from the transition.
1456 receiver->map()->LookupTransition(*holder, *name, lookup);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001457 if (!lookup->IsTransition()) return false;
1458 PropertyDetails target_details =
1459 lookup->GetTransitionDetails(receiver->map());
1460 if (target_details.IsReadOnly()) return false;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001461
1462 // If the value that's being stored does not fit in the field that the
1463 // instance would transition to, create a new transition that fits the value.
1464 // This has to be done before generating the IC, since that IC will embed the
1465 // transition target.
1466 // Ensure the instance and its map were migrated before trying to update the
1467 // transition target.
1468 ASSERT(!receiver->map()->is_deprecated());
1469 if (!value->FitsRepresentation(target_details.representation())) {
1470 Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map()));
1471 Map::GeneralizeRepresentation(
rossberg@chromium.org92597162013-08-23 13:28:00 +00001472 target, target->LastAdded(),
1473 value->OptimalRepresentation(), FORCE_FIELD);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001474 // Lookup the transition again since the transition tree may have changed
1475 // entirely by the migration above.
1476 receiver->map()->LookupTransition(*holder, *name, lookup);
1477 if (!lookup->IsTransition()) return false;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001478 ic->MarkMonomorphicPrototypeFailure();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001479 }
1480 return true;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001481}
1482
1483
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001484MaybeObject* StoreIC::Store(Handle<Object> object,
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001485 Handle<String> name,
1486 Handle<Object> value,
1487 JSReceiver::StoreFromKeyed store_mode) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001488 if (MigrateDeprecated(object) || object->IsJSProxy()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001489 Handle<Object> result = JSReceiver::SetProperty(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001490 Handle<JSReceiver>::cast(object), name, value, NONE, strict_mode());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001491 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1492 return *result;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001493 }
1494
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001495 // If the object is undefined or null it's illegal to try to set any
1496 // properties on it; throw a TypeError in that case.
1497 if (object->IsUndefined() || object->IsNull()) {
1498 return TypeError("non_object_property_store", object, name);
1499 }
1500
1501 // The length property of string values is read-only. Throw in strict mode.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001502 if (strict_mode() == kStrictMode && object->IsString() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001503 name->Equals(isolate()->heap()->length_string())) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001504 return TypeError("strict_read_only_property", object, name);
1505 }
1506
1507 // Ignore other stores where the receiver is not a JSObject.
1508 // TODO(1475): Must check prototype chains of object wrappers.
1509 if (!object->IsJSObject()) return *value;
1510
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001511 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1512
1513 // Check if the given name is an array index.
1514 uint32_t index;
1515 if (name->AsArrayIndex(&index)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001516 Handle<Object> result =
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001517 JSObject::SetElement(receiver, index, value, NONE, strict_mode());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001518 RETURN_IF_EMPTY_HANDLE(isolate(), result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001519 return *value;
1520 }
1521
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001522 // Observed objects are always modified through the runtime.
1523 if (FLAG_harmony_observation && receiver->map()->is_observed()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001524 Handle<Object> result = JSReceiver::SetProperty(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001525 receiver, name, value, NONE, strict_mode(), store_mode);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001526 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1527 return *result;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001528 }
1529
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001530 // Use specialized code for setting the length of arrays with fast
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001531 // properties. Slow properties might indicate redefinition of the length
danno@chromium.org1bc70ab2013-07-14 22:07:11 +00001532 // property. Note that when redefined using Object.freeze, it's possible
1533 // to have fast properties but a read-only length.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001534 if (FLAG_use_ic &&
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001535 receiver->IsJSArray() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001536 name->Equals(isolate()->heap()->length_string()) &&
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001537 Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() &&
danno@chromium.org1bc70ab2013-07-14 22:07:11 +00001538 receiver->HasFastProperties() &&
1539 !receiver->map()->is_frozen()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001540 Handle<Code> stub =
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001541 StoreArrayLengthStub(kind(), strict_mode()).GetCode(isolate());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001542 set_target(*stub);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001543 TRACE_IC("StoreIC", name);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001544 Handle<Object> result = JSReceiver::SetProperty(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001545 receiver, name, value, NONE, strict_mode(), store_mode);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001546 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1547 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 }
1549
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001550 if (receiver->IsJSGlobalProxy()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001551 if (FLAG_use_ic && kind() != Code::KEYED_STORE_IC) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001552 // Generate a generic stub that goes to the runtime when we see a global
1553 // proxy as receiver.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001554 Handle<Code> stub = global_proxy_stub();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001555 set_target(*stub);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001556 TRACE_IC("StoreIC", name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001557 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001558 Handle<Object> result = JSReceiver::SetProperty(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001559 receiver, name, value, NONE, strict_mode(), store_mode);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001560 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1561 return *result;
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001562 }
1563
1564 LookupResult lookup(isolate());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001565 bool can_store = LookupForWrite(receiver, name, value, &lookup, this);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001566 if (!can_store &&
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001567 strict_mode() == kStrictMode &&
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001568 !(lookup.IsProperty() && lookup.IsReadOnly()) &&
1569 IsUndeclaredGlobal(object)) {
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00001570 // Strict mode doesn't allow setting non-existent global property.
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001571 return ReferenceError("not_defined", name);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001572 }
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001573 if (FLAG_use_ic) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001574 if (state() == UNINITIALIZED) {
1575 Handle<Code> stub = pre_monomorphic_stub();
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001576 set_target(*stub);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001577 TRACE_IC("StoreIC", name);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001578 } else if (can_store) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001579 UpdateCaches(&lookup, receiver, name, value);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001580 } else if (!name->IsCacheable(isolate()) ||
1581 lookup.IsNormal() ||
1582 (lookup.IsField() && lookup.CanHoldValue(value))) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001583 Handle<Code> stub = generic_stub();
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001584 set_target(*stub);
1585 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001586 }
1587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 // Set the property.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001589 Handle<Object> result = JSReceiver::SetProperty(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001590 receiver, name, value, NONE, strict_mode(), store_mode);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001591 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1592 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001593}
1594
1595
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001596void StoreIC::UpdateCaches(LookupResult* lookup,
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001597 Handle<JSObject> receiver,
1598 Handle<String> name,
1599 Handle<Object> value) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001600 ASSERT(!receiver->IsJSGlobalProxy());
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001601 ASSERT(lookup->IsFound());
1602
danno@chromium.orgc612e022011-11-10 11:38:15 +00001603 // These are not cacheable, so we never see such LookupResults here.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001604 ASSERT(!lookup->IsHandler());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001606 Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001608 PatchCache(receiver, name, code);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001609 TRACE_IC("StoreIC", name);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001610}
1611
1612
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001613Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001614 Handle<Object> object,
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001615 Handle<String> name,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001616 Handle<Object> value,
1617 InlineCacheHolderFlag cache_holder) {
1618 ASSERT(cache_holder == OWN_MAP);
1619 // This is currently guaranteed by checks in StoreIC::Store.
1620 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1621
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001622 Handle<JSObject> holder(lookup->holder());
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001623 StoreStubCompiler compiler(isolate(), strict_mode(), kind());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001624 switch (lookup->type()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001625 case FIELD:
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001626 return compiler.CompileStoreField(receiver, lookup, name);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001627 case TRANSITION: {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001628 // Explicitly pass in the receiver map since LookupForWrite may have
1629 // stored something else than the receiver in the holder.
1630 Handle<Map> transition(
1631 lookup->GetTransitionTarget(receiver->map()), isolate());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001632 int descriptor = transition->LastAdded();
1633
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001634 DescriptorArray* target_descriptors = transition->instance_descriptors();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001635 PropertyDetails details = target_descriptors->GetDetails(descriptor);
1636
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001637 if (details.type() == CALLBACKS || details.attributes() != NONE) break;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001638
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001639 return compiler.CompileStoreTransition(
1640 receiver, lookup, transition, name);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001641 }
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001642 case NORMAL:
1643 if (kind() == Code::KEYED_STORE_IC) break;
1644 if (receiver->IsGlobalObject()) {
1645 // The stub generated for the global object picks the value directly
1646 // from the property cell. So the property must be directly on the
1647 // global object.
1648 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001649 Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate());
1650 Handle<Type> union_type = PropertyCell::UpdatedType(cell, value);
1651 StoreGlobalStub stub(strict_mode(), union_type->IsConstant());
1652
1653 Handle<Code> code = stub.GetCodeCopyFromTemplate(
1654 isolate(), receiver->map(), *cell);
1655 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1656 HeapObject::UpdateMapCodeCache(receiver, name, code);
1657 return code;
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001658 }
1659 ASSERT(holder.is_identical_to(receiver));
1660 return strict_mode() == kStrictMode
1661 ? isolate()->builtins()->StoreIC_Normal_Strict()
1662 : isolate()->builtins()->StoreIC_Normal();
1663 case CALLBACKS: {
1664 if (kind() == Code::KEYED_STORE_IC) break;
1665 Handle<Object> callback(lookup->GetCallbackObject(), isolate());
1666 if (callback->IsExecutableAccessorInfo()) {
1667 Handle<ExecutableAccessorInfo> info =
1668 Handle<ExecutableAccessorInfo>::cast(callback);
1669 if (v8::ToCData<Address>(info->setter()) == 0) break;
1670 if (!holder->HasFastProperties()) break;
1671 if (!info->IsCompatibleReceiver(*receiver)) break;
1672 return compiler.CompileStoreCallback(receiver, holder, name, info);
1673 } else if (callback->IsAccessorPair()) {
1674 Handle<Object> setter(
1675 Handle<AccessorPair>::cast(callback)->setter(), isolate());
1676 if (!setter->IsJSFunction()) break;
1677 if (holder->IsGlobalObject()) break;
1678 if (!holder->HasFastProperties()) break;
1679 Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
1680 CallOptimization call_optimization(function);
1681 if (call_optimization.is_simple_api_call() &&
1682 call_optimization.IsCompatibleReceiver(*receiver)) {
1683 return compiler.CompileStoreCallback(
1684 receiver, holder, name, call_optimization);
1685 }
1686 return compiler.CompileStoreViaSetter(
1687 receiver, holder, name, Handle<JSFunction>::cast(setter));
1688 }
1689 // TODO(dcarney): Handle correctly.
1690 if (callback->IsDeclaredAccessorInfo()) break;
1691 ASSERT(callback->IsForeign());
1692 // No IC support for old-style native accessors.
1693 break;
1694 }
1695 case INTERCEPTOR:
1696 if (kind() == Code::KEYED_STORE_IC) break;
1697 ASSERT(HasInterceptorSetter(*receiver));
1698 return compiler.CompileStoreInterceptor(receiver, name);
1699 case CONSTANT:
1700 break;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001701 case NONEXISTENT:
danno@chromium.orgc612e022011-11-10 11:38:15 +00001702 case HANDLER:
danno@chromium.orgc612e022011-11-10 11:38:15 +00001703 UNREACHABLE();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001704 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001705 }
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001706 return slow_stub();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001707}
1708
1709
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001710Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001711 KeyedAccessStoreMode store_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001712 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1713 // via megamorphic stubs, since they don't have a map in their relocation info
1714 // and so the stubs can't be harvested for the object needed for a map check.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001715 if (target()->type() != Code::NORMAL) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001716 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type");
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001717 return generic_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001718 }
1719
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001720 Handle<Map> receiver_map(receiver->map(), isolate());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001721 if (state() == UNINITIALIZED || state() == PREMONOMORPHIC) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001722 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
1723 // yet will do so and stay there.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001724 Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, store_mode);
1725 store_mode = GetNonTransitioningStoreMode(store_mode);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001726 return isolate()->stub_cache()->ComputeKeyedStoreElement(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001727 monomorphic_map, strict_mode(), store_mode);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001728 }
1729
ulan@chromium.org750145a2013-03-07 15:14:13 +00001730 MapHandleList target_receiver_maps;
1731 target()->FindAllMaps(&target_receiver_maps);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001732 if (target_receiver_maps.length() == 0) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001733 // In the case that there is a non-map-specific IC is installed (e.g. keyed
1734 // stores into properties in dictionary mode), then there will be not
1735 // receiver maps in the target.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001736 return generic_stub();
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001737 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001738
1739 // There are several special cases where an IC that is MONOMORPHIC can still
1740 // transition to a different GetNonTransitioningStoreMode IC that handles a
1741 // superset of the original IC. Handle those here if the receiver map hasn't
1742 // changed or it has transitioned to a more general kind.
1743 KeyedAccessStoreMode old_store_mode =
1744 Code::GetKeyedAccessStoreMode(target()->extra_ic_state());
1745 Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001746 if (state() == MONOMORPHIC) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001747 // If the "old" and "new" maps are in the same elements map family, stay
1748 // MONOMORPHIC and use the map for the most generic ElementsKind.
1749 Handle<Map> transitioned_receiver_map = receiver_map;
1750 if (IsTransitionStoreMode(store_mode)) {
1751 transitioned_receiver_map =
1752 ComputeTransitionedMap(receiver, store_mode);
1753 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001754 if (IsTransitionedMapOfMonomorphicTarget(*transitioned_receiver_map)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001755 // Element family is the same, use the "worst" case map.
1756 store_mode = GetNonTransitioningStoreMode(store_mode);
1757 return isolate()->stub_cache()->ComputeKeyedStoreElement(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001758 transitioned_receiver_map, strict_mode(), store_mode);
danno@chromium.org169691d2013-07-15 08:01:13 +00001759 } else if (*previous_receiver_map == receiver->map() &&
1760 old_store_mode == STANDARD_STORE &&
1761 (IsGrowStoreMode(store_mode) ||
1762 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1763 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1764 // A "normal" IC that handles stores can switch to a version that can
1765 // grow at the end of the array, handle OOB accesses or copy COW arrays
1766 // and still stay MONOMORPHIC.
1767 return isolate()->stub_cache()->ComputeKeyedStoreElement(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001768 receiver_map, strict_mode(), store_mode);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001769 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001770 }
1771
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001772 ASSERT(state() != GENERIC);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001773
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001774 bool map_added =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001775 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001776
ulan@chromium.org750145a2013-03-07 15:14:13 +00001777 if (IsTransitionStoreMode(store_mode)) {
1778 Handle<Map> transitioned_receiver_map =
1779 ComputeTransitionedMap(receiver, store_mode);
1780 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1781 transitioned_receiver_map);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001782 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001783
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001784 if (!map_added) {
1785 // If the miss wasn't due to an unseen map, a polymorphic stub
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001786 // won't help, use the generic stub.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001787 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice");
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001788 return generic_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001789 }
1790
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001791 // If the maximum number of receiver maps has been exceeded, use the generic
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001792 // version of the IC.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001793 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001794 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded");
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001795 return generic_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001796 }
1797
ulan@chromium.org750145a2013-03-07 15:14:13 +00001798 // Make sure all polymorphic handlers have the same store mode, otherwise the
1799 // generic stub must be used.
1800 store_mode = GetNonTransitioningStoreMode(store_mode);
1801 if (old_store_mode != STANDARD_STORE) {
1802 if (store_mode == STANDARD_STORE) {
1803 store_mode = old_store_mode;
1804 } else if (store_mode != old_store_mode) {
1805 TRACE_GENERIC_IC(isolate(), "KeyedIC", "store mode mismatch");
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001806 return generic_stub();
ulan@chromium.org750145a2013-03-07 15:14:13 +00001807 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001808 }
1809
jkummerow@chromium.org91efda92013-03-25 16:32:26 +00001810 // If the store mode isn't the standard mode, make sure that all polymorphic
1811 // receivers are either external arrays, or all "normal" arrays. Otherwise,
1812 // use the generic stub.
1813 if (store_mode != STANDARD_STORE) {
1814 int external_arrays = 0;
1815 for (int i = 0; i < target_receiver_maps.length(); ++i) {
1816 if (target_receiver_maps[i]->has_external_array_elements()) {
1817 external_arrays++;
1818 }
1819 }
1820 if (external_arrays != 0 &&
1821 external_arrays != target_receiver_maps.length()) {
1822 TRACE_GENERIC_IC(isolate(), "KeyedIC",
1823 "unsupported combination of external and normal arrays");
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001824 return generic_stub();
jkummerow@chromium.org91efda92013-03-25 16:32:26 +00001825 }
1826 }
1827
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001828 return isolate()->stub_cache()->ComputeStoreElementPolymorphic(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001829 &target_receiver_maps, store_mode, strict_mode());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001830}
1831
1832
ulan@chromium.org750145a2013-03-07 15:14:13 +00001833Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1834 Handle<JSObject> receiver,
1835 KeyedAccessStoreMode store_mode) {
1836 switch (store_mode) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001837 case STORE_TRANSITION_SMI_TO_OBJECT:
1838 case STORE_TRANSITION_DOUBLE_TO_OBJECT:
1839 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
1840 case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001841 return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001842 case STORE_TRANSITION_SMI_TO_DOUBLE:
1843 case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001844 return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001845 case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
1846 case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1847 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
1848 case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001849 return JSObject::GetElementsTransitionMap(receiver,
1850 FAST_HOLEY_ELEMENTS);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001851 case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1852 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001853 return JSObject::GetElementsTransitionMap(receiver,
1854 FAST_HOLEY_DOUBLE_ELEMENTS);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001855 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
1856 ASSERT(receiver->map()->has_external_array_elements());
1857 // Fall through
1858 case STORE_NO_TRANSITION_HANDLE_COW:
1859 case STANDARD_STORE:
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001860 case STORE_AND_GROW_NO_TRANSITION:
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001861 return Handle<Map>(receiver->map(), isolate());
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001862 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001863 return Handle<Map>::null();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001864}
1865
1866
ulan@chromium.org750145a2013-03-07 15:14:13 +00001867bool IsOutOfBoundsAccess(Handle<JSObject> receiver,
1868 int index) {
1869 if (receiver->IsJSArray()) {
1870 return JSArray::cast(*receiver)->length()->IsSmi() &&
1871 index >= Smi::cast(JSArray::cast(*receiver)->length())->value();
1872 }
1873 return index >= receiver->elements()->length();
1874}
1875
1876
1877KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
1878 Handle<Object> key,
1879 Handle<Object> value) {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001880 ASSERT(!key->ToSmi()->IsFailure());
1881 Smi* smi_key = NULL;
1882 key->ToSmi()->To(&smi_key);
1883 int index = smi_key->value();
ulan@chromium.org750145a2013-03-07 15:14:13 +00001884 bool oob_access = IsOutOfBoundsAccess(receiver, index);
1885 bool allow_growth = receiver->IsJSArray() && oob_access;
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001886 if (allow_growth) {
1887 // Handle growing array in stub if necessary.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001888 if (receiver->HasFastSmiElements()) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001889 if (value->IsHeapNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001890 if (receiver->HasFastHoleyElements()) {
1891 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1892 } else {
1893 return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE;
1894 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001895 }
1896 if (value->IsHeapObject()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001897 if (receiver->HasFastHoleyElements()) {
1898 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT;
1899 } else {
1900 return STORE_AND_GROW_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_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
1907 } else {
1908 return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT;
1909 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001910 }
1911 }
1912 return STORE_AND_GROW_NO_TRANSITION;
1913 } else {
1914 // Handle only in-bounds elements accesses.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001915 if (receiver->HasFastSmiElements()) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001916 if (value->IsHeapNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001917 if (receiver->HasFastHoleyElements()) {
1918 return STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE;
1919 } else {
1920 return STORE_TRANSITION_SMI_TO_DOUBLE;
1921 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001922 } else if (value->IsHeapObject()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001923 if (receiver->HasFastHoleyElements()) {
1924 return STORE_TRANSITION_HOLEY_SMI_TO_OBJECT;
1925 } else {
1926 return STORE_TRANSITION_SMI_TO_OBJECT;
1927 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001928 }
1929 } else if (receiver->HasFastDoubleElements()) {
1930 if (!value->IsSmi() && !value->IsHeapNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001931 if (receiver->HasFastHoleyElements()) {
1932 return STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
1933 } else {
1934 return STORE_TRANSITION_DOUBLE_TO_OBJECT;
1935 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001936 }
1937 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001938 if (!FLAG_trace_external_array_abuse &&
1939 receiver->map()->has_external_array_elements() && oob_access) {
1940 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001941 }
1942 Heap* heap = receiver->GetHeap();
1943 if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
1944 return STORE_NO_TRANSITION_HANDLE_COW;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001945 } else {
1946 return STANDARD_STORE;
1947 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001948 }
1949}
1950
1951
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001952MaybeObject* KeyedStoreIC::StoreForceGeneric(Handle<Object> object,
1953 Handle<Object> key,
1954 Handle<Object> value) {
1955 set_target(*generic_stub());
1956 Handle<Object> result = Runtime::SetObjectProperty(isolate(), object,
1957 key,
1958 value,
1959 NONE,
1960 strict_mode());
1961 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1962 return *result;
1963}
1964
1965
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001966MaybeObject* KeyedStoreIC::Store(Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001967 Handle<Object> key,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001968 Handle<Object> value) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001969 if (MigrateDeprecated(object)) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001970 Handle<Object> result = Runtime::SetObjectProperty(isolate(), object,
1971 key,
1972 value,
1973 NONE,
1974 strict_mode());
1975 RETURN_IF_EMPTY_HANDLE(isolate(), result);
1976 return *result;
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00001977 }
1978
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001979 // Check for values that can be converted into an internalized string directly
1980 // or is representable as a smi.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001981 key = TryConvertKey(key, isolate());
1982
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00001983 MaybeObject* maybe_object = NULL;
1984 Handle<Code> stub = generic_stub();
1985
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001986 if (key->IsInternalizedString()) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00001987 maybe_object = StoreIC::Store(object,
1988 Handle<String>::cast(key),
1989 value,
1990 JSReceiver::MAY_BE_STORE_FROM_KEYED);
1991 if (maybe_object->IsFailure()) return maybe_object;
1992 } else {
1993 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() &&
1994 !(FLAG_harmony_observation && object->IsJSObject() &&
1995 JSObject::cast(*object)->map()->is_observed());
1996 if (use_ic && !object->IsSmi()) {
1997 // Don't use ICs for maps of the objects in Array's prototype chain. We
1998 // expect to be able to trap element sets to objects with those maps in
1999 // the runtime to enable optimization of element hole access.
2000 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2001 if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false;
2002 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002003
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00002004 if (use_ic) {
2005 ASSERT(!object->IsJSGlobalProxy());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002006
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002007 if (object->IsJSObject()) {
2008 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
2009 bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure();
2010 if (receiver->elements()->map() ==
2011 isolate()->heap()->non_strict_arguments_elements_map()) {
2012 stub = non_strict_arguments_stub();
2013 } else if (key_is_smi_like &&
2014 !(target().is_identical_to(non_strict_arguments_stub()))) {
2015 // We should go generic if receiver isn't a dictionary, but our
2016 // prototype chain does have dictionary elements. This ensures that
2017 // other non-dictionary receivers in the polymorphic case benefit
2018 // from fast path keyed stores.
2019 if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) {
2020 KeyedAccessStoreMode store_mode =
2021 GetStoreMode(receiver, key, value);
2022 stub = StoreElementStub(receiver, store_mode);
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00002023 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00002024 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002025 }
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00002026 }
2027 }
2028
2029 if (!is_target_set()) {
2030 if (*stub == *generic_stub()) {
2031 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic");
ager@chromium.org3811b432009-10-28 14:53:37 +00002032 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002033 ASSERT(!stub.is_null());
2034 set_target(*stub);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002035 TRACE_IC("StoreIC", key);
ager@chromium.org3811b432009-10-28 14:53:37 +00002036 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002037
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00002038 if (maybe_object) return maybe_object;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002039 Handle<Object> result = Runtime::SetObjectProperty(isolate(), object, key,
2040 value,
2041 NONE,
2042 strict_mode());
2043 RETURN_IF_EMPTY_HANDLE(isolate(), result);
2044 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002045}
2046
2047
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002048#undef TRACE_IC
2049
2050
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051// ----------------------------------------------------------------------------
2052// Static IC stub generators.
2053//
2054
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002055// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002056RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002057 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002058 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002059 CallIC ic(isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002060 Handle<Object> receiver = args.at<Object>(0);
2061 Handle<String> key = args.at<String>(1);
2062 ic.UpdateState(receiver, key);
2063 MaybeObject* maybe_result = ic.LoadFunction(receiver, key);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002064 JSFunction* raw_function;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002065 if (!maybe_result->To(&raw_function)) return maybe_result;
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002066
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002067 // The first time the inline cache is updated may be the first time the
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002068 // function it references gets called. If the function is lazily compiled
2069 // then the first call will trigger a compilation. We check for this case
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002070 // and we do the compilation immediately, instead of waiting for the stub
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002071 // currently attached to the JSFunction object to trigger compilation.
2072 if (raw_function->is_compiled()) return raw_function;
2073
2074 Handle<JSFunction> function(raw_function);
2075 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
2076 return *function;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002077}
2078
2079
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002080// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002081RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002082 HandleScope scope(isolate);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002083 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002084 KeyedCallIC ic(isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002085 Handle<Object> receiver = args.at<Object>(0);
2086 Handle<Object> key = args.at<Object>(1);
2087 ic.UpdateState(receiver, key);
2088 MaybeObject* maybe_result = ic.LoadFunction(receiver, key);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002089 // Result could be a function or a failure.
2090 JSFunction* raw_function = NULL;
2091 if (!maybe_result->To(&raw_function)) return maybe_result;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002092
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002093 if (raw_function->is_compiled()) return raw_function;
2094
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002095 Handle<JSFunction> function(raw_function, isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002096 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
2097 return *function;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002098}
2099
2100
2101// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002102RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002103 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002104 ASSERT(args.length() == 2);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002105 LoadIC ic(IC::NO_EXTRA_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.Load(receiver, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002110}
2111
2112
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002113// Used from ic-<arch>.cc
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002114RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002115 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002116 ASSERT(args.length() == 2);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002117 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002118 Handle<Object> receiver = args.at<Object>(0);
2119 Handle<Object> key = args.at<Object>(1);
2120 ic.UpdateState(receiver, key);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002121 return ic.Load(receiver, key);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002122}
2123
2124
2125RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure) {
2126 HandleScope scope(isolate);
2127 ASSERT(args.length() == 2);
2128 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002129 Handle<Object> receiver = args.at<Object>(0);
2130 Handle<Object> key = args.at<Object>(1);
2131 ic.UpdateState(receiver, key);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002132 return ic.Load(receiver, key);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002133}
2134
2135
2136RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002137 HandleScope scope(isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002138 ASSERT(args.length() == 2);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002139 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002140 Handle<Object> receiver = args.at<Object>(0);
2141 Handle<Object> key = args.at<Object>(1);
2142 ic.UpdateState(receiver, key);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002143 return ic.LoadForceGeneric(receiver, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002144}
2145
2146
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002147// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002148RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002149 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002150 ASSERT(args.length() == 3);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002151 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002152 Handle<Object> receiver = args.at<Object>(0);
2153 Handle<String> key = args.at<String>(1);
2154 ic.UpdateState(receiver, key);
2155 return ic.Store(receiver, key, args.at<Object>(2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002156}
2157
2158
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002159RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure) {
2160 HandleScope scope(isolate);
2161 ASSERT(args.length() == 3);
2162 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002163 Handle<Object> receiver = args.at<Object>(0);
2164 Handle<String> key = args.at<String>(1);
2165 ic.UpdateState(receiver, key);
2166 return ic.Store(receiver, key, args.at<Object>(2));
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002167}
2168
2169
machenbach@chromium.orgea468882013-11-18 08:53:19 +00002170RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_MissFromStubFailure) {
2171 HandleScope scope(isolate);
2172 ASSERT(args.length() == 2);
2173 KeyedCallIC ic(isolate);
2174 Arguments* caller_args = reinterpret_cast<Arguments*>(args[0]);
2175 Handle<Object> key = args.at<Object>(1);
2176 Handle<Object> receiver((*caller_args)[0], isolate);
2177
2178 ic.UpdateState(receiver, key);
2179 MaybeObject* maybe_result = ic.LoadFunction(receiver, key);
2180 // Result could be a function or a failure.
2181 JSFunction* raw_function = NULL;
2182 if (!maybe_result->To(&raw_function)) return maybe_result;
2183
2184 if (raw_function->is_compiled()) return raw_function;
2185
2186 Handle<JSFunction> function(raw_function, isolate);
2187 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
2188 return *function;
2189}
2190
2191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002192RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002193 SealHandleScope shs(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00002194
2195 ASSERT(args.length() == 2);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002196 JSArray* receiver = JSArray::cast(args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00002197 Object* len = args[1];
2198
lrn@chromium.org303ada72010-10-27 09:33:13 +00002199 // The generated code should filter out non-Smis before we get here.
2200 ASSERT(len->IsSmi());
2201
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002202#ifdef DEBUG
2203 // The length property has to be a writable callback property.
2204 LookupResult debug_lookup(isolate);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002205 receiver->LocalLookup(isolate->heap()->length_string(), &debug_lookup);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002206 ASSERT(debug_lookup.IsPropertyCallbacks() && !debug_lookup.IsReadOnly());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002207#endif
2208
lrn@chromium.org303ada72010-10-27 09:33:13 +00002209 Object* result;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002210 MaybeObject* maybe_result = receiver->SetElementsLength(len);
2211 if (!maybe_result->To(&result)) return maybe_result;
2212
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002213 return len;
ager@chromium.org5c838252010-02-19 08:53:10 +00002214}
2215
2216
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002217// Extend storage is called in a store inline cache when
2218// it is necessary to extend the properties array of a
2219// JSObject.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002220RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002221 SealHandleScope shs(isolate);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002222 ASSERT(args.length() == 3);
2223
2224 // Convert the parameters
2225 JSObject* object = JSObject::cast(args[0]);
2226 Map* transition = Map::cast(args[1]);
2227 Object* value = args[2];
2228
2229 // Check the object has run out out property space.
2230 ASSERT(object->HasFastProperties());
2231 ASSERT(object->map()->unused_property_fields() == 0);
2232
2233 // Expand the properties array.
2234 FixedArray* old_storage = object->properties();
2235 int new_unused = transition->unused_property_fields();
2236 int new_size = old_storage->length() + new_unused + 1;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002237 Object* result;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002238 MaybeObject* maybe_result = old_storage->CopySize(new_size);
2239 if (!maybe_result->ToObject(&result)) return maybe_result;
2240
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002241 FixedArray* new_storage = FixedArray::cast(result);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002242
2243 Object* to_store = value;
2244
2245 if (FLAG_track_double_fields) {
2246 DescriptorArray* descriptors = transition->instance_descriptors();
2247 PropertyDetails details = descriptors->GetDetails(transition->LastAdded());
2248 if (details.representation().IsDouble()) {
2249 MaybeObject* maybe_storage =
2250 isolate->heap()->AllocateHeapNumber(value->Number());
2251 if (!maybe_storage->To(&to_store)) return maybe_storage;
2252 }
2253 }
2254
2255 new_storage->set(old_storage->length(), to_store);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002256
ager@chromium.org32912102009-01-16 10:38:43 +00002257 // Set the new property value and do the map transition.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002258 object->set_properties(new_storage);
2259 object->set_map(transition);
2260
2261 // Return the stored value.
2262 return value;
2263}
2264
2265
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002266// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002267RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002268 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002269 ASSERT(args.length() == 3);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002270 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002271 Handle<Object> receiver = args.at<Object>(0);
2272 Handle<Object> key = args.at<Object>(1);
2273 ic.UpdateState(receiver, key);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002274 return ic.Store(receiver, key, args.at<Object>(2));
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002275}
2276
2277
2278RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure) {
2279 HandleScope scope(isolate);
2280 ASSERT(args.length() == 3);
2281 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002282 Handle<Object> receiver = args.at<Object>(0);
2283 Handle<Object> key = args.at<Object>(1);
2284 ic.UpdateState(receiver, key);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002285 return ic.Store(receiver, key, args.at<Object>(2));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002286}
2287
2288
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002289RUNTIME_FUNCTION(MaybeObject*, StoreIC_Slow) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002290 HandleScope scope(isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002291 ASSERT(args.length() == 3);
2292 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002293 Handle<Object> object = args.at<Object>(0);
2294 Handle<Object> key = args.at<Object>(1);
2295 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002296 StrictModeFlag strict_mode = ic.strict_mode();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002297 Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key,
2298 value,
2299 NONE,
2300 strict_mode);
2301 RETURN_IF_EMPTY_HANDLE(isolate, result);
2302 return *result;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002303}
2304
2305
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002306RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002307 HandleScope scope(isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002308 ASSERT(args.length() == 3);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002309 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002310 Handle<Object> object = args.at<Object>(0);
2311 Handle<Object> key = args.at<Object>(1);
2312 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002313 StrictModeFlag strict_mode = ic.strict_mode();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002314 Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key,
2315 value,
2316 NONE,
2317 strict_mode);
2318 RETURN_IF_EMPTY_HANDLE(isolate, result);
2319 return *result;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002320}
2321
2322
2323RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002324 HandleScope scope(isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002325 ASSERT(args.length() == 3);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002326 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002327 Handle<Object> receiver = args.at<Object>(0);
2328 Handle<Object> key = args.at<Object>(1);
2329 ic.UpdateState(receiver, key);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002330 return ic.StoreForceGeneric(receiver, key, args.at<Object>(2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002331}
2332
2333
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00002334RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002335 HandleScope scope(isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00002336 ASSERT(args.length() == 4);
2337 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00002338 Handle<Object> value = args.at<Object>(0);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002339 Handle<Map> map = args.at<Map>(1);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00002340 Handle<Object> key = args.at<Object>(2);
2341 Handle<Object> object = args.at<Object>(3);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002342 StrictModeFlag strict_mode = ic.strict_mode();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002343 if (object->IsJSObject()) {
2344 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
2345 map->elements_kind());
2346 }
2347 Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key,
2348 value,
2349 NONE,
2350 strict_mode);
2351 RETURN_IF_EMPTY_HANDLE(isolate, result);
2352 return *result;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00002353}
2354
2355
danno@chromium.org40cb8782011-05-25 07:58:50 +00002356const char* BinaryOpIC::GetName(TypeInfo type_info) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002357 switch (type_info) {
2358 case UNINITIALIZED: return "Uninitialized";
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002359 case SMI: return "Smi";
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002360 case INT32: return "Int32";
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002361 case NUMBER: return "Number";
lrn@chromium.org7516f052011-03-30 08:52:27 +00002362 case ODDBALL: return "Oddball";
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002363 case STRING: return "String";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002364 case GENERIC: return "Generic";
2365 default: return "Invalid";
2366 }
2367}
2368
2369
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002370MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) {
2371 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
2372 BinaryOpStub stub(extra_ic_state);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002373
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002374 Handle<Type> left_type = stub.GetLeftType(isolate());
2375 Handle<Type> right_type = stub.GetRightType(isolate());
2376 bool smi_was_enabled = left_type->Maybe(Type::Smi()) &&
2377 right_type->Maybe(Type::Smi());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002378
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002379 Maybe<Handle<Object> > result = stub.Result(left, right, isolate());
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00002380 if (!result.has_value) return Failure::Exception();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002381
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002382#ifdef DEBUG
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002383 if (FLAG_trace_ic) {
2384 char buffer[100];
2385 NoAllocationStringAllocator allocator(buffer,
2386 static_cast<unsigned>(sizeof(buffer)));
2387 StringStream stream(&allocator);
2388 stream.Add("[");
2389 stub.PrintName(&stream);
2390
2391 stub.UpdateStatus(left, right, result);
2392
2393 stream.Add(" => ");
2394 stub.PrintState(&stream);
2395 stream.Add(" ");
2396 stream.OutputToStdOut();
2397 PrintF(" @ %p <- ", static_cast<void*>(*stub.GetCode(isolate())));
2398 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
2399 PrintF("]\n");
2400 } else {
2401 stub.UpdateStatus(left, right, result);
2402 }
2403#else
2404 stub.UpdateStatus(left, right, result);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002405#endif
2406
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002407 Handle<Code> code = stub.GetCode(isolate());
2408 set_target(*code);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002409
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002410 left_type = stub.GetLeftType(isolate());
2411 right_type = stub.GetRightType(isolate());
2412 bool enable_smi = left_type->Maybe(Type::Smi()) &&
2413 right_type->Maybe(Type::Smi());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002414
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002415 if (!smi_was_enabled && enable_smi) {
2416 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2417 } else if (smi_was_enabled && !enable_smi) {
2418 PatchInlinedSmiCode(address(), DISABLE_INLINED_SMI_CHECK);
2419 }
2420
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00002421 ASSERT(result.has_value);
2422 return static_cast<MaybeObject*>(*result.value);
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002423}
2424
2425
2426RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002427 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002428 Handle<Object> left = args.at<Object>(0);
2429 Handle<Object> right = args.at<Object>(1);
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002430 BinaryOpIC ic(isolate);
2431 return ic.Transition(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002432}
2433
2434
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00002435Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002436 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002437 Code* code = NULL;
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00002438 CHECK(stub.FindCodeInCache(&code, isolate));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002439 return code;
2440}
2441
2442
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002443Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002444 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002445 return stub.GetCode(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002446}
2447
2448
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002449const char* CompareIC::GetStateName(State state) {
2450 switch (state) {
2451 case UNINITIALIZED: return "UNINITIALIZED";
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002452 case SMI: return "SMI";
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002453 case NUMBER: return "NUMBER";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002454 case INTERNALIZED_STRING: return "INTERNALIZED_STRING";
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002455 case STRING: return "STRING";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002456 case UNIQUE_NAME: return "UNIQUE_NAME";
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002457 case OBJECT: return "OBJECT";
2458 case KNOWN_OBJECT: return "KNOWN_OBJECT";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002459 case GENERIC: return "GENERIC";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002460 }
danno@chromium.org41728482013-06-12 22:31:22 +00002461 UNREACHABLE();
2462 return NULL;
2463}
2464
2465
2466Handle<Type> CompareIC::StateToType(
2467 Isolate* isolate,
2468 CompareIC::State state,
2469 Handle<Map> map) {
2470 switch (state) {
2471 case CompareIC::UNINITIALIZED:
2472 return handle(Type::None(), isolate);
2473 case CompareIC::SMI:
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002474 return handle(Type::Smi(), isolate);
danno@chromium.org41728482013-06-12 22:31:22 +00002475 case CompareIC::NUMBER:
2476 return handle(Type::Number(), isolate);
2477 case CompareIC::STRING:
2478 return handle(Type::String(), isolate);
2479 case CompareIC::INTERNALIZED_STRING:
2480 return handle(Type::InternalizedString(), isolate);
2481 case CompareIC::UNIQUE_NAME:
2482 return handle(Type::UniqueName(), isolate);
2483 case CompareIC::OBJECT:
2484 return handle(Type::Receiver(), isolate);
2485 case CompareIC::KNOWN_OBJECT:
2486 return handle(
2487 map.is_null() ? Type::Receiver() : Type::Class(map), isolate);
2488 case CompareIC::GENERIC:
2489 return handle(Type::Any(), isolate);
2490 }
2491 UNREACHABLE();
2492 return Handle<Type>();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002493}
2494
2495
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002496void CompareIC::StubInfoToType(int stub_minor_key,
2497 Handle<Type>* left_type,
2498 Handle<Type>* right_type,
2499 Handle<Type>* overall_type,
2500 Handle<Map> map,
2501 Isolate* isolate) {
2502 State left_state, right_state, handler_state;
2503 ICCompareStub::DecodeMinorKey(stub_minor_key, &left_state, &right_state,
2504 &handler_state, NULL);
2505 *left_type = StateToType(isolate, left_state);
2506 *right_type = StateToType(isolate, right_state);
2507 *overall_type = StateToType(isolate, handler_state, map);
2508}
2509
2510
2511CompareIC::State CompareIC::NewInputState(State old_state,
2512 Handle<Object> value) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002513 switch (old_state) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002514 case UNINITIALIZED:
2515 if (value->IsSmi()) return SMI;
2516 if (value->IsHeapNumber()) return NUMBER;
2517 if (value->IsInternalizedString()) return INTERNALIZED_STRING;
2518 if (value->IsString()) return STRING;
2519 if (value->IsSymbol()) return UNIQUE_NAME;
2520 if (value->IsJSObject()) return OBJECT;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002521 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002522 case SMI:
2523 if (value->IsSmi()) return SMI;
2524 if (value->IsHeapNumber()) return NUMBER;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002525 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002526 case NUMBER:
2527 if (value->IsNumber()) return NUMBER;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002528 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002529 case INTERNALIZED_STRING:
2530 if (value->IsInternalizedString()) return INTERNALIZED_STRING;
2531 if (value->IsString()) return STRING;
2532 if (value->IsSymbol()) return UNIQUE_NAME;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002533 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002534 case STRING:
2535 if (value->IsString()) return STRING;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002536 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002537 case UNIQUE_NAME:
2538 if (value->IsUniqueName()) return UNIQUE_NAME;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002539 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002540 case OBJECT:
2541 if (value->IsJSObject()) return OBJECT;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002542 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002543 case GENERIC:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002544 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002545 case KNOWN_OBJECT:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002546 UNREACHABLE();
2547 break;
2548 }
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002549 return GENERIC;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002550}
2551
2552
2553CompareIC::State CompareIC::TargetState(State old_state,
2554 State old_left,
2555 State old_right,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002556 bool has_inlined_smi_code,
2557 Handle<Object> x,
2558 Handle<Object> y) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002559 switch (old_state) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002560 case UNINITIALIZED:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002561 if (x->IsSmi() && y->IsSmi()) return SMI;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002562 if (x->IsNumber() && y->IsNumber()) return NUMBER;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002563 if (Token::IsOrderedRelationalCompareOp(op_)) {
2564 // Ordered comparisons treat undefined as NaN, so the
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002565 // NUMBER stub will do the right thing.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002566 if ((x->IsNumber() && y->IsUndefined()) ||
2567 (y->IsNumber() && x->IsUndefined())) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002568 return NUMBER;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002569 }
2570 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002571 if (x->IsInternalizedString() && y->IsInternalizedString()) {
2572 // We compare internalized strings as plain ones if we need to determine
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002573 // the order in a non-equality compare.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002574 return Token::IsEqualityOp(op_) ? INTERNALIZED_STRING : STRING;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002575 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002576 if (x->IsString() && y->IsString()) return STRING;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002577 if (!Token::IsEqualityOp(op_)) return GENERIC;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002578 if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002579 if (x->IsJSObject() && y->IsJSObject()) {
2580 if (Handle<JSObject>::cast(x)->map() ==
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002581 Handle<JSObject>::cast(y)->map()) {
2582 return KNOWN_OBJECT;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002583 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002584 return OBJECT;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002585 }
2586 }
2587 return GENERIC;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002588 case SMI:
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002589 return x->IsNumber() && y->IsNumber() ? NUMBER : GENERIC;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002590 case INTERNALIZED_STRING:
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002591 ASSERT(Token::IsEqualityOp(op_));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002592 if (x->IsString() && y->IsString()) return STRING;
2593 if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
2594 return GENERIC;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002595 case NUMBER:
2596 // If the failure was due to one side changing from smi to heap number,
2597 // then keep the state (if other changed at the same time, we will get
2598 // a second miss and then go to generic).
2599 if (old_left == SMI && x->IsHeapNumber()) return NUMBER;
2600 if (old_right == SMI && y->IsHeapNumber()) return NUMBER;
2601 return GENERIC;
2602 case KNOWN_OBJECT:
2603 ASSERT(Token::IsEqualityOp(op_));
2604 if (x->IsJSObject() && y->IsJSObject()) return OBJECT;
2605 return GENERIC;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002606 case STRING:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002607 case UNIQUE_NAME:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002608 case OBJECT:
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002609 case GENERIC:
2610 return GENERIC;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002611 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002612 UNREACHABLE();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002613 return GENERIC; // Make the compiler happy.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002614}
2615
2616
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002617Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002618 HandleScope scope(isolate());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002619 State previous_left, previous_right, previous_state;
2620 ICCompareStub::DecodeMinorKey(target()->stub_info(), &previous_left,
2621 &previous_right, &previous_state, NULL);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002622 State new_left = NewInputState(previous_left, x);
2623 State new_right = NewInputState(previous_right, y);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002624 State state = TargetState(previous_state, previous_left, previous_right,
2625 HasInlinedSmiCode(address()), x, y);
2626 ICCompareStub stub(op_, new_left, new_right, state);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002627 if (state == KNOWN_OBJECT) {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002628 stub.set_known_map(
2629 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate()));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002630 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002631 Handle<Code> new_target = stub.GetCode(isolate());
2632 set_target(*new_target);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002633
2634#ifdef DEBUG
2635 if (FLAG_trace_ic) {
2636 PrintF("[CompareIC in ");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002637 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002638 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
2639 GetStateName(previous_left),
2640 GetStateName(previous_right),
2641 GetStateName(previous_state),
2642 GetStateName(new_left),
2643 GetStateName(new_right),
2644 GetStateName(state),
2645 Token::Name(op_),
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002646 static_cast<void*>(*stub.GetCode(isolate())));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002647 }
2648#endif
2649
2650 // Activate inlined smi code.
2651 if (previous_state == UNINITIALIZED) {
2652 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
2653 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002654
2655 return *new_target;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002656}
2657
2658
2659// Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002660RUNTIME_FUNCTION(Code*, CompareIC_Miss) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002661 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002662 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002663 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002664 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002665}
2666
2667
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002668void CompareNilIC::Clear(Address address, Code* target) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002669 if (IsCleared(target)) return;
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002670 Code::ExtraICState state = target->extended_extra_ic_state();
2671
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002672 CompareNilICStub stub(state, HydrogenCodeStub::UNINITIALIZED);
danno@chromium.org41728482013-06-12 22:31:22 +00002673 stub.ClearState();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002674
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002675 Code* code = NULL;
2676 CHECK(stub.FindCodeInCache(&code, target->GetIsolate()));
2677
2678 SetTargetAtAddress(address, code);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002679}
2680
2681
ulan@chromium.org837a67e2013-06-11 15:39:48 +00002682MaybeObject* CompareNilIC::DoCompareNilSlow(NilValue nil,
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002683 Handle<Object> object) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002684 if (object->IsNull() || object->IsUndefined()) {
2685 return Smi::FromInt(true);
2686 }
2687 return Smi::FromInt(object->IsUndetectableObject());
2688}
2689
2690
2691MaybeObject* CompareNilIC::CompareNil(Handle<Object> object) {
2692 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
2693
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002694 CompareNilICStub stub(extra_ic_state);
2695
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002696 // Extract the current supported types from the patched IC and calculate what
2697 // types must be supported as a result of the miss.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002698 bool already_monomorphic = stub.IsMonomorphic();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002699
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002700 stub.UpdateStatus(object);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002701
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002702 NilValue nil = stub.GetNilValue();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002703
2704 // Find or create the specialized stub to support the new set of types.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002705 Handle<Code> code;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002706 if (stub.IsMonomorphic()) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002707 Handle<Map> monomorphic_map(already_monomorphic
2708 ? target()->FindFirstMap()
2709 : HeapObject::cast(*object)->map());
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002710 code = isolate()->stub_cache()->ComputeCompareNil(monomorphic_map, stub);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002711 } else {
2712 code = stub.GetCode(isolate());
2713 }
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002714 set_target(*code);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00002715 return DoCompareNilSlow(nil, object);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002716}
2717
2718
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002719RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss) {
2720 HandleScope scope(isolate);
2721 Handle<Object> object = args.at<Object>(0);
2722 CompareNilIC ic(isolate);
2723 return ic.CompareNil(object);
2724}
2725
2726
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002727RUNTIME_FUNCTION(MaybeObject*, Unreachable) {
2728 UNREACHABLE();
2729 CHECK(false);
2730 return isolate->heap()->undefined_value();
2731}
2732
2733
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002734Builtins::JavaScript BinaryOpIC::TokenToJSBuiltin(Token::Value op) {
2735 switch (op) {
2736 default:
2737 UNREACHABLE();
2738 case Token::ADD:
2739 return Builtins::ADD;
2740 break;
2741 case Token::SUB:
2742 return Builtins::SUB;
2743 break;
2744 case Token::MUL:
2745 return Builtins::MUL;
2746 break;
2747 case Token::DIV:
2748 return Builtins::DIV;
2749 break;
2750 case Token::MOD:
2751 return Builtins::MOD;
2752 break;
2753 case Token::BIT_OR:
2754 return Builtins::BIT_OR;
2755 break;
2756 case Token::BIT_AND:
2757 return Builtins::BIT_AND;
2758 break;
2759 case Token::BIT_XOR:
2760 return Builtins::BIT_XOR;
2761 break;
2762 case Token::SAR:
2763 return Builtins::SAR;
2764 break;
2765 case Token::SHR:
2766 return Builtins::SHR;
2767 break;
2768 case Token::SHL:
2769 return Builtins::SHL;
2770 break;
2771 }
2772}
2773
2774
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002775MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object) {
2776 ToBooleanStub stub(target()->extended_extra_ic_state());
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002777 bool to_boolean_value = stub.UpdateStatus(object);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002778 Handle<Code> code = stub.GetCode(isolate());
2779 set_target(*code);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00002780 return Smi::FromInt(to_boolean_value ? 1 : 0);
2781}
2782
2783
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002784RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss) {
2785 ASSERT(args.length() == 1);
2786 HandleScope scope(isolate);
2787 Handle<Object> object = args.at<Object>(0);
2788 ToBooleanIC ic(isolate);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002789 return ic.ToBoolean(object);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00002790}
2791
2792
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002793static const Address IC_utilities[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002794#define ADDR(name) FUNCTION_ADDR(name),
2795 IC_UTIL_LIST(ADDR)
2796 NULL
2797#undef ADDR
2798};
2799
2800
2801Address IC::AddressFromUtilityId(IC::UtilityId id) {
2802 return IC_utilities[id];
2803}
2804
2805
2806} } // namespace v8::internal