blob: f0f5c302b325e0928848416ae20f8ec21ba6869f [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,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000074 Handle<Object> name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000075 State old_state,
lrn@chromium.org34e60782011-09-15 07:25:40 +000076 Code* new_target) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077 if (FLAG_trace_ic) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000078 Object* undef = new_target->GetHeap()->undefined_value();
79 State new_state = StateFrom(new_target, undef, undef);
ager@chromium.orgea91cc52011-05-23 06:06:11 +000080 PrintF("[%s in ", type);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000081 Isolate* isolate = new_target->GetIsolate();
82 StackFrameIterator it(isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +000083 while (it.frame()->fp() != this->fp()) it.Advance();
84 StackFrame* raw_frame = it.frame();
85 if (raw_frame->is_internal()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +000086 Code* apply_builtin = isolate->builtins()->builtin(
87 Builtins::kFunctionApply);
88 if (raw_frame->unchecked_code() == apply_builtin) {
89 PrintF("apply from ");
90 it.Advance();
91 raw_frame = it.frame();
92 }
93 }
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000094 JavaScriptFrame::PrintTop(isolate, stdout, false, true);
ulan@chromium.org750145a2013-03-07 15:14:13 +000095 Code::ExtraICState state = new_target->extra_ic_state();
96 const char* modifier =
97 GetTransitionMarkModifier(Code::GetKeyedAccessStoreMode(state));
ulan@chromium.org65a89c22012-02-14 11:46:07 +000098 PrintF(" (%c->%c%s)",
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099 TransitionMarkFromState(old_state),
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000100 TransitionMarkFromState(new_state),
ulan@chromium.org750145a2013-03-07 15:14:13 +0000101 modifier);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000102 name->Print();
103 PrintF("]\n");
104 }
105}
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000106
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000107#define TRACE_GENERIC_IC(isolate, type, reason) \
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000108 do { \
109 if (FLAG_trace_ic) { \
110 PrintF("[%s patching generic stub in ", type); \
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000111 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000112 PrintF(" (%s)]\n", reason); \
113 } \
114 } while (false)
115
116#else
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000117#define TRACE_GENERIC_IC(isolate, type, reason)
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000118#endif // DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000119
120#define TRACE_IC(type, name, old_state, new_target) \
121 ASSERT((TraceIC(type, name, old_state, new_target), true))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000123IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) {
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000124 // To improve the performance of the (much used) IC code, we unfold a few
125 // levels of the stack frame iteration code. This yields a ~35% speedup when
126 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
127 const Address entry =
128 Isolate::c_entry_fp(isolate->thread_local_top());
129 Address* pc_address =
130 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
131 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
132 // If there's another JavaScript frame on the stack or a
133 // StubFailureTrampoline, we need to look one frame further down the stack to
134 // find the frame pointer and the return address stack slot.
135 if (depth == EXTRA_CALL_FRAME) {
136 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
137 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
138 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
139 }
140#ifdef DEBUG
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000141 StackFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142 for (int i = 0; i < depth + 1; i++) it.Advance();
143 StackFrame* frame = it.frame();
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000144 ASSERT(fp == frame->fp() && pc_address == frame->pc_address());
145#endif
146 fp_ = fp;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000147 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000148}
149
150
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000151#ifdef ENABLE_DEBUGGER_SUPPORT
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000152Address IC::OriginalCodeAddress() const {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000153 HandleScope scope(isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000154 // Compute the JavaScript frame for the frame pointer of this IC
155 // structure. We need this to be able to find the function
156 // corresponding to the frame.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000157 StackFrameIterator it(isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158 while (it.frame()->fp() != this->fp()) it.Advance();
159 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
160 // Find the function on the stack and both the active code for the
161 // function and the original code.
danno@chromium.org169691d2013-07-15 08:01:13 +0000162 JSFunction* function = frame->function();
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000163 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000164 Code* code = shared->code();
165 ASSERT(Debug::HasDebugInfo(shared));
166 Code* original_code = Debug::GetDebugInfo(shared)->original_code();
167 ASSERT(original_code->IsCode());
168 // Get the address of the call site in the active code. This is the
169 // place where the call to DebugBreakXXX is and where the IC
170 // normally would be.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000171 Address addr = Assembler::target_address_from_return_address(pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172 // Return the address in the original code. This is the place where
ager@chromium.org32912102009-01-16 10:38:43 +0000173 // the call which has been overwritten by the DebugBreakXXX resides
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000174 // and the place where the inline cache system should look.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000175 intptr_t delta =
176 original_code->instruction_start() - code->instruction_start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000177 return addr + delta;
178}
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000179#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000180
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000181
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000182static bool TryRemoveInvalidPrototypeDependentStub(Code* target,
183 Object* receiver,
184 Object* name) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000185 if (target->is_keyed_load_stub() ||
186 target->is_keyed_call_stub() ||
187 target->is_keyed_store_stub()) {
188 // Determine whether the failure is due to a name failure.
189 if (!name->IsName()) return false;
190 Name* stub_name = target->FindFirstName();
191 if (Name::cast(name) != stub_name) return false;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000192 }
193
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000194 InlineCacheHolderFlag cache_holder =
195 Code::ExtractCacheHolderFromFlags(target->flags());
196
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000197 Isolate* isolate = target->GetIsolate();
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000198 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) {
199 // The stub was generated for JSObject but called for non-JSObject.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000200 // IC::GetCodeCacheHolder is not applicable.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000201 return false;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000202 } else if (cache_holder == PROTOTYPE_MAP &&
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000203 receiver->GetPrototype(isolate)->IsNull()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000204 // IC::GetCodeCacheHolder is not applicable.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000205 return false;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000206 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000207 Map* map = IC::GetCodeCacheHolder(isolate, receiver, cache_holder)->map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000208
209 // Decide whether the inline cache failed because of changes to the
210 // receiver itself or changes to one of its prototypes.
211 //
212 // If there are changes to the receiver itself, the map of the
213 // receiver will have changed and the current target will not be in
214 // the receiver map's code cache. Therefore, if the current target
215 // is in the receiver map's code cache, the inline cache failed due
216 // to prototype check failure.
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +0000217 int index = map->IndexInCodeCache(name, target);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000218 if (index >= 0) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000219 map->RemoveFromCodeCache(String::cast(name), target, index);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000220 // For loads and stores, handlers are stored in addition to the ICs on the
221 // map. Remove those, too.
222 if ((target->is_load_stub() || target->is_keyed_load_stub() ||
223 target->is_store_stub() || target->is_keyed_store_stub()) &&
224 target->type() != Code::NORMAL) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000225 Code* handler = target->FindFirstCode();
226 index = map->IndexInCodeCache(name, handler);
227 if (index >= 0) {
228 map->RemoveFromCodeCache(String::cast(name), handler, index);
229 }
230 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000231 return true;
232 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000234 // The stub is not in the cache. We've ruled out all other kinds of failure
235 // except for proptotype chain changes, a deprecated map, a map that's
236 // different from the one that the stub expects, or a constant global property
237 // that will become mutable. Threat all those situations as prototype failures
238 // (stay monomorphic if possible).
239
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000240 // If the IC is shared between multiple receivers (slow dictionary mode), then
241 // the map cannot be deprecated and the stub invalidated.
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000242 if (cache_holder == OWN_MAP) {
243 Map* old_map = target->FindFirstMap();
244 if (old_map == map) return true;
245 if (old_map != NULL && old_map->is_deprecated()) return true;
246 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000247
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000248 if (receiver->IsGlobalObject()) {
249 if (!name->IsName()) return false;
250 Isolate* isolate = target->GetIsolate();
251 LookupResult lookup(isolate);
252 GlobalObject* global = GlobalObject::cast(receiver);
253 global->LocalLookupRealNamedProperty(Name::cast(name), &lookup);
254 if (!lookup.IsFound()) return false;
255 PropertyCell* cell = global->GetPropertyCell(&lookup);
256 return cell->type()->IsConstant();
257 }
258
259 return false;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000260}
261
262
263IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
264 IC::State state = target->ic_state();
265
266 if (state != MONOMORPHIC || !name->IsString()) return state;
267 if (receiver->IsUndefined() || receiver->IsNull()) return state;
268
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000269 Code::Kind kind = target->kind();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000270 // Remove the target from the code cache if it became invalid
271 // because of changes in the prototype chain to avoid hitting it
272 // again.
273 // Call stubs handle this later to allow extra IC state
274 // transitions.
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000275 if (kind != Code::CALL_IC && kind != Code::KEYED_CALL_IC &&
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000276 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000277 return MONOMORPHIC_PROTOTYPE_FAILURE;
278 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000279
280 // The builtins object is special. It only changes when JavaScript
281 // builtins are loaded lazily. It is important to keep inline
282 // caches for the builtins object monomorphic. Therefore, if we get
283 // an inline cache miss for the builtins object after lazily loading
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 // JavaScript builtins, we return uninitialized as the state to
285 // force the inline cache back to monomorphic state.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000286 if (receiver->IsJSBuiltinsObject()) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000287 return UNINITIALIZED;
288 }
289
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000290 return MONOMORPHIC;
291}
292
293
ager@chromium.org236ad962008-09-25 09:45:57 +0000294RelocInfo::Mode IC::ComputeMode() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000295 Address addr = address();
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000296 Code* code = Code::cast(isolate()->FindCodeObject(addr));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297 for (RelocIterator it(code, RelocInfo::kCodeTargetMask);
298 !it.done(); it.next()) {
299 RelocInfo* info = it.rinfo();
300 if (info->pc() == addr) return info->rmode();
301 }
302 UNREACHABLE();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000303 return RelocInfo::NONE32;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304}
305
306
307Failure* IC::TypeError(const char* type,
308 Handle<Object> object,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000309 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000310 HandleScope scope(isolate());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000311 Handle<Object> args[2] = { key, object };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000312 Handle<Object> error = isolate()->factory()->NewTypeError(
313 type, HandleVector(args, 2));
314 return isolate()->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000315}
316
317
318Failure* IC::ReferenceError(const char* type, Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000319 HandleScope scope(isolate());
320 Handle<Object> error = isolate()->factory()->NewReferenceError(
321 type, HandleVector(&name, 1));
322 return isolate()->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323}
324
325
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000326static int ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state) {
327 bool was_uninitialized =
328 old_state == UNINITIALIZED || old_state == PREMONOMORPHIC;
329 bool is_uninitialized =
330 new_state == UNINITIALIZED || new_state == PREMONOMORPHIC;
331 return (was_uninitialized && !is_uninitialized) ? 1 :
332 (!was_uninitialized && is_uninitialized) ? -1 : 0;
333}
334
335
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000336void IC::PostPatching(Address address, Code* target, Code* old_target) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000337 if (FLAG_type_info_threshold == 0 && !FLAG_watch_ic_patching) {
338 return;
339 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000340 Isolate* isolate = target->GetHeap()->isolate();
341 Code* host = isolate->
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000342 inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
343 if (host->kind() != Code::FUNCTION) return;
344
345 if (FLAG_type_info_threshold > 0 &&
346 old_target->is_inline_cache_stub() &&
347 target->is_inline_cache_stub()) {
348 int delta = ComputeTypeInfoCountDelta(old_target->ic_state(),
349 target->ic_state());
350 // Not all Code objects have TypeFeedbackInfo.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000351 if (host->type_feedback_info()->IsTypeFeedbackInfo() && delta != 0) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000352 TypeFeedbackInfo* info =
353 TypeFeedbackInfo::cast(host->type_feedback_info());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000354 info->change_ic_with_type_info_count(delta);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000355 }
356 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000357 if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
358 TypeFeedbackInfo* info =
359 TypeFeedbackInfo::cast(host->type_feedback_info());
360 info->change_own_type_change_checksum();
361 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000362 if (FLAG_watch_ic_patching) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000363 host->set_profiler_ticks(0);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000364 isolate->runtime_profiler()->NotifyICChanged();
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000365 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000366 // TODO(2029): When an optimized function is patched, it would
367 // be nice to propagate the corresponding type information to its
368 // unoptimized version for the benefit of later inlining.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000369}
370
371
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000372void IC::Clear(Address address) {
373 Code* target = GetTargetAtAddress(address);
374
375 // Don't clear debug break inline cache as it will remove the break point.
yangguo@chromium.org9768bf12013-01-11 14:51:07 +0000376 if (target->is_debug_break()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000377
378 switch (target->kind()) {
379 case Code::LOAD_IC: return LoadIC::Clear(address, target);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000380 case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 case Code::STORE_IC: return StoreIC::Clear(address, target);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000382 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 case Code::CALL_IC: return CallIC::Clear(address, target);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000384 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000385 case Code::COMPARE_IC: return CompareIC::Clear(address, target);
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000386 case Code::COMPARE_NIL_IC: return CompareNilIC::Clear(address, target);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000387 case Code::UNARY_OP_IC:
388 case Code::BINARY_OP_IC:
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000389 case Code::TO_BOOLEAN_IC:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000390 // Clearing these is tricky and does not
391 // make any performance difference.
392 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000393 default: UNREACHABLE();
394 }
395}
396
397
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000398void CallICBase::Clear(Address address, Code* target) {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000399 if (target->ic_state() == UNINITIALIZED) return;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000400 bool contextual = CallICBase::Contextual::decode(target->extra_ic_state());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000401 Code* code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000402 Isolate::Current()->stub_cache()->FindCallInitialize(
403 target->arguments_count(),
danno@chromium.org40cb8782011-05-25 07:58:50 +0000404 contextual ? RelocInfo::CODE_TARGET_CONTEXT : RelocInfo::CODE_TARGET,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 target->kind());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000406 SetTargetAtAddress(address, code);
407}
408
409
410void KeyedLoadIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000411 if (target->ic_state() == UNINITIALIZED) return;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000412 // Make sure to also clear the map used in inline fast cases. If we
413 // do not clear these maps, cached code can keep objects alive
414 // through the embedded maps.
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000415 SetTargetAtAddress(address, *initialize_stub());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416}
417
418
419void LoadIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000420 if (target->ic_state() == UNINITIALIZED) return;
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000421 SetTargetAtAddress(address, *initialize_stub());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000422}
423
424
425void StoreIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000426 if (target->ic_state() == UNINITIALIZED) return;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000427 SetTargetAtAddress(address,
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000428 (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode)
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000429 ? *initialize_stub_strict()
430 : *initialize_stub());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431}
432
433
434void KeyedStoreIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000435 if (target->ic_state() == UNINITIALIZED) return;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000436 SetTargetAtAddress(address,
ulan@chromium.org65a89c22012-02-14 11:46:07 +0000437 (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode)
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000438 ? *initialize_stub_strict()
439 : *initialize_stub());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440}
441
442
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000443void CompareIC::Clear(Address address, Code* target) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000444 ASSERT(target->major_key() == CodeStub::CompareIC);
445 CompareIC::State handler_state;
446 Token::Value op;
447 ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL,
448 &handler_state, &op);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000449 // Only clear CompareICs that can retain objects.
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000450 if (handler_state != KNOWN_OBJECT) return;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000451 SetTargetAtAddress(address, GetRawUninitialized(op));
452 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
453}
454
455
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000456static bool HasInterceptorGetter(JSObject* object) {
457 return !object->GetNamedInterceptor()->getter()->IsUndefined();
458}
459
460
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000461static void LookupForRead(Handle<Object> object,
462 Handle<String> name,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000463 LookupResult* lookup) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000464 // Skip all the objects with named interceptors, but
465 // without actual getter.
466 while (true) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000467 object->Lookup(*name, lookup);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000468 // Besides normal conditions (property not found or it's not
ager@chromium.org5c838252010-02-19 08:53:10 +0000469 // an interceptor), bail out if lookup is not cacheable: we won't
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000470 // be able to IC it anyway and regular lookup should work fine.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000471 if (!lookup->IsInterceptor() || !lookup->IsCacheable()) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000472 return;
473 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000474
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000475 Handle<JSObject> holder(lookup->holder(), lookup->isolate());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000476 if (HasInterceptorGetter(*holder)) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000477 return;
478 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000479
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 holder->LocalLookupRealNamedProperty(*name, lookup);
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000481 if (lookup->IsFound()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000482 ASSERT(!lookup->IsInterceptor());
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000483 return;
484 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000485
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000486 Handle<Object> proto(holder->GetPrototype(), lookup->isolate());
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000487 if (proto->IsNull()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000488 ASSERT(!lookup->IsFound());
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000489 return;
490 }
491
492 object = proto;
493 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000494}
495
496
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000497Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) {
498 Handle<Object> delegate = Execution::GetFunctionDelegate(object);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000499
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000500 if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000501 // Patch the receiver and use the delegate as the function to
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000502 // invoke. This is used for invoking objects as if they were functions.
503 const int argc = target()->arguments_count();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000504 StackFrameLocator locator(isolate());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000505 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
506 int index = frame->ComputeExpressionsCount() - (argc + 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000507 frame->SetExpression(index, *object);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000508 }
509
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000510 return delegate;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000511}
512
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000513
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000514void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee,
515 Handle<Object> object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000516 while (callee->IsJSFunctionProxy()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000517 callee = Handle<Object>(JSFunctionProxy::cast(*callee)->call_trap(),
518 isolate());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000519 }
520
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000521 if (callee->IsJSFunction()) {
522 Handle<JSFunction> function = Handle<JSFunction>::cast(callee);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000523 if (!function->shared()->is_classic_mode() || function->IsBuiltin()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000524 // Do not wrap receiver for strict mode functions or for builtins.
525 return;
526 }
527 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000528
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000529 // And only wrap string, number or boolean.
530 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
531 // Change the receiver to the result of calling ToObject on it.
532 const int argc = this->target()->arguments_count();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000533 StackFrameLocator locator(isolate());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000534 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
535 int index = frame->ComputeExpressionsCount() - (argc + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000536 frame->SetExpression(index, *isolate()->factory()->ToObject(object));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000537 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000538}
539
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000540
lrn@chromium.org303ada72010-10-27 09:33:13 +0000541MaybeObject* CallICBase::LoadFunction(State state,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000542 Code::ExtraICState extra_ic_state,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000543 Handle<Object> object,
544 Handle<String> name) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000545 if (object->IsJSObject()) {
546 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
547 if (receiver->map()->is_deprecated()) {
548 JSObject::MigrateInstance(receiver);
549 }
550 }
551
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000552 // If the object is undefined or null it's illegal to try to get any
553 // of its properties; throw a TypeError in that case.
554 if (object->IsUndefined() || object->IsNull()) {
555 return TypeError("non_object_property_call", object, name);
556 }
557
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000558 // Check if the name is trivially convertible to an index and get
559 // the element if so.
560 uint32_t index;
561 if (name->AsArrayIndex(&index)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000562 Handle<Object> result = Object::GetElement(object, index);
563 RETURN_IF_EMPTY_HANDLE(isolate(), result);
564 if (result->IsJSFunction()) return *result;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000565
566 // Try to find a suitable function delegate for the object at hand.
567 result = TryCallAsFunction(result);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000568 if (result->IsJSFunction()) return *result;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000569
570 // Otherwise, it will fail in the lookup step.
571 }
572
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573 // Lookup the property in the object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000574 LookupResult lookup(isolate());
575 LookupForRead(object, name, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000576
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000577 if (!lookup.IsFound()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000578 // If the object does not have the requested property, check which
579 // exception we need to throw.
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +0000580 return IsUndeclaredGlobal(object)
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000581 ? ReferenceError("not_defined", name)
582 : TypeError("undefined_method", object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000583 }
584
585 // Lookup is valid: Update inline cache and stub cache.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000586 if (FLAG_use_ic) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000587 UpdateCaches(&lookup, state, extra_ic_state, object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588 }
589
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000590 // Get the property.
591 PropertyAttributes attr;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000592 Handle<Object> result =
593 Object::GetProperty(object, object, &lookup, name, &attr);
594 RETURN_IF_EMPTY_HANDLE(isolate(), result);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000595
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000596 if (lookup.IsInterceptor() && attr == ABSENT) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000597 // If the object does not have the requested property, check which
598 // exception we need to throw.
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +0000599 return IsUndeclaredGlobal(object)
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000600 ? ReferenceError("not_defined", name)
601 : TypeError("undefined_method", object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000602 }
603
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000604 ASSERT(!result->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000605
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000606 // Make receiver an object if the callee requires it. Strict mode or builtin
607 // functions do not wrap the receiver, non-strict functions and objects
608 // called as functions do.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000609 ReceiverToObjectIfRequired(result, object);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000610
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000611 if (result->IsJSFunction()) {
612 Handle<JSFunction> function = Handle<JSFunction>::cast(result);
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000613#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000614 // Handle stepping into a function if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000615 Debug* debug = isolate()->debug();
616 if (debug->StepInActive()) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000617 // Protect the result in a handle as the debugger can allocate and might
618 // cause GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 debug->HandleStepIn(function, object, fp(), false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000621#endif
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000622 return *function;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 }
624
625 // Try to find a suitable function delegate for the object at hand.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000626 result = TryCallAsFunction(result);
627 if (result->IsJSFunction()) return *result;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000628
629 return TypeError("property_not_function", object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630}
631
632
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000633bool CallICBase::TryUpdateExtraICState(LookupResult* lookup,
634 Handle<Object> object,
635 Code::ExtraICState* extra_ic_state) {
636 ASSERT(kind_ == Code::CALL_IC);
637 if (lookup->type() != CONSTANT_FUNCTION) return false;
638 JSFunction* function = lookup->GetConstantFunction();
639 if (!function->shared()->HasBuiltinFunctionId()) return false;
640
641 // Fetch the arguments passed to the called function.
642 const int argc = target()->arguments_count();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000643 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000644 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
645 Arguments args(argc + 1,
646 &Memory::Object_at(fp +
647 StandardFrameConstants::kCallerSPOffset +
648 argc * kPointerSize));
649 switch (function->shared()->builtin_function_id()) {
650 case kStringCharCodeAt:
651 case kStringCharAt:
652 if (object->IsString()) {
653 String* string = String::cast(*object);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000654 // Check there's the right string value or wrapper in the receiver slot.
655 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000656 // If we're in the default (fastest) state and the index is
657 // out of bounds, update the state to record this fact.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000658 if (StringStubState::decode(*extra_ic_state) == DEFAULT_STRING_STUB &&
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000659 argc >= 1 && args[1]->IsNumber()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000660 double index = DoubleToInteger(args.number_at(1));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000661 if (index < 0 || index >= string->length()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000662 *extra_ic_state =
663 StringStubState::update(*extra_ic_state,
664 STRING_INDEX_OUT_OF_BOUNDS);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000665 return true;
666 }
667 }
668 }
669 break;
670 default:
671 return false;
672 }
673 return false;
674}
675
676
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000677Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup,
678 State state,
679 Code::ExtraICState extra_state,
680 Handle<Object> object,
681 Handle<String> name) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000682 int argc = target()->arguments_count();
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000683 Handle<JSObject> holder(lookup->holder(), isolate());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000684 switch (lookup->type()) {
685 case FIELD: {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000686 PropertyIndex index = lookup->GetFieldIndex();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000687 return isolate()->stub_cache()->ComputeCallField(
688 argc, kind_, extra_state, name, object, holder, index);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000689 }
690 case CONSTANT_FUNCTION: {
691 // Get the constant function and compute the code stub for this
692 // call; used for rewriting to monomorphic state and making sure
693 // that the code stub is in the stub cache.
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000694 Handle<JSFunction> function(lookup->GetConstantFunction(), isolate());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000695 return isolate()->stub_cache()->ComputeCallConstant(
696 argc, kind_, extra_state, name, object, holder, function);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000697 }
698 case NORMAL: {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000699 // If we return a null handle, the IC will not be patched.
700 if (!object->IsJSObject()) return Handle<Code>::null();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000701 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
702
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000703 if (holder->IsGlobalObject()) {
704 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000705 Handle<PropertyCell> cell(
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000706 global->GetPropertyCell(lookup), isolate());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000707 if (!cell->value()->IsJSFunction()) return Handle<Code>::null();
708 Handle<JSFunction> function(JSFunction::cast(cell->value()));
709 return isolate()->stub_cache()->ComputeCallGlobal(
710 argc, kind_, extra_state, name, receiver, global, cell, function);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000711 } else {
712 // There is only one shared stub for calling normalized
713 // properties. It does not traverse the prototype chain, so the
714 // property must be found in the receiver for the stub to be
715 // applicable.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000716 if (!holder.is_identical_to(receiver)) return Handle<Code>::null();
717 return isolate()->stub_cache()->ComputeCallNormal(
718 argc, kind_, extra_state);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000719 }
720 break;
721 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000722 case INTERCEPTOR:
723 ASSERT(HasInterceptorGetter(*holder));
724 return isolate()->stub_cache()->ComputeCallInterceptor(
725 argc, kind_, extra_state, name, object, holder);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000726 default:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000727 return Handle<Code>::null();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000728 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000729}
730
731
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000732void CallICBase::UpdateCaches(LookupResult* lookup,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000733 State state,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000734 Code::ExtraICState extra_ic_state,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000735 Handle<Object> object,
736 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000737 // Bail out if we didn't find a result.
ager@chromium.org5c838252010-02-19 08:53:10 +0000738 if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739
740 // Compute the number of arguments.
741 int argc = target()->arguments_count();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000742 Handle<Code> code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743 if (state == UNINITIALIZED) {
744 // This is the first time we execute this inline cache.
745 // Set the target to the pre monomorphic stub to delay
746 // setting the monomorphic state.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000747 code = isolate()->stub_cache()->ComputeCallPreMonomorphic(
748 argc, kind_, extra_ic_state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000749 } else if (state == MONOMORPHIC) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000750 if (kind_ == Code::CALL_IC &&
751 TryUpdateExtraICState(lookup, object, &extra_ic_state)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000752 code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
753 object, name);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000754 } else if (TryRemoveInvalidPrototypeDependentStub(target(),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000755 *object,
756 *name)) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000757 state = MONOMORPHIC_PROTOTYPE_FAILURE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000758 code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
759 object, name);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000760 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000761 code = isolate()->stub_cache()->ComputeCallMegamorphic(
762 argc, kind_, extra_ic_state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000763 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000764 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000765 code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
766 object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000767 }
768
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000769 // If there's no appropriate stub we simply avoid updating the caches.
770 if (code.is_null()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771
772 // Patch the call site depending on the state of the cache.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000773 switch (state) {
774 case UNINITIALIZED:
775 case MONOMORPHIC_PROTOTYPE_FAILURE:
776 case PREMONOMORPHIC:
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000777 case MONOMORPHIC:
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000778 set_target(*code);
779 break;
780 case MEGAMORPHIC: {
781 // Cache code holding map should be consistent with
782 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub.
783 Handle<JSObject> cache_object = object->IsJSObject()
784 ? Handle<JSObject>::cast(object)
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +0000785 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())),
786 isolate());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000787 // Update the stub cache.
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000788 UpdateMegamorphicCache(cache_object->map(), *name, *code);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000789 break;
790 }
yangguo@chromium.org9768bf12013-01-11 14:51:07 +0000791 case DEBUG_STUB:
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000792 break;
793 case POLYMORPHIC:
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000794 case GENERIC:
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000795 UNREACHABLE();
796 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000797 }
798
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000799 TRACE_IC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
800 name, state, target());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000801}
802
803
lrn@chromium.org303ada72010-10-27 09:33:13 +0000804MaybeObject* KeyedCallIC::LoadFunction(State state,
805 Handle<Object> object,
806 Handle<Object> key) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000807 if (key->IsInternalizedString()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000808 return CallICBase::LoadFunction(state,
809 Code::kNoExtraICState,
810 object,
811 Handle<String>::cast(key));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000812 }
813
danno@chromium.orgf005df62013-04-30 16:36:45 +0000814 if (object->IsJSObject()) {
815 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
816 if (receiver->map()->is_deprecated()) {
817 JSObject::MigrateInstance(receiver);
818 }
819 }
820
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000821 if (object->IsUndefined() || object->IsNull()) {
822 return TypeError("non_object_property_call", object, key);
823 }
824
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000825 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
826 ASSERT(!(use_ic && object->IsJSGlobalProxy()));
827
828 if (use_ic && state != MEGAMORPHIC) {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000829 int argc = target()->arguments_count();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000830 Handle<Code> stub = isolate()->stub_cache()->ComputeCallMegamorphic(
831 argc, Code::KEYED_CALL_IC, Code::kNoExtraICState);
832 if (object->IsJSObject()) {
833 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
834 if (receiver->elements()->map() ==
835 isolate()->heap()->non_strict_arguments_elements_map()) {
836 stub = isolate()->stub_cache()->ComputeCallArguments(argc);
837 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000838 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000839 ASSERT(!stub.is_null());
840 set_target(*stub);
841 TRACE_IC("KeyedCallIC", key, state, target());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000842 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000843
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000844 Handle<Object> result = GetProperty(isolate(), object, key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000845 RETURN_IF_EMPTY_HANDLE(isolate(), result);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000846
847 // Make receiver an object if the callee requires it. Strict mode or builtin
848 // functions do not wrap the receiver, non-strict functions and objects
849 // called as functions do.
850 ReceiverToObjectIfRequired(result, object);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000851 if (result->IsJSFunction()) return *result;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000852
853 result = TryCallAsFunction(result);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000854 if (result->IsJSFunction()) return *result;
855
856 return TypeError("property_not_function", object, key);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000857}
858
859
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000860MaybeObject* LoadIC::Load(State state,
861 Handle<Object> object,
862 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 // If the object is undefined or null it's illegal to try to get any
864 // of its properties; throw a TypeError in that case.
865 if (object->IsUndefined() || object->IsNull()) {
866 return TypeError("non_object_property_load", object, name);
867 }
868
869 if (FLAG_use_ic) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000870 // Use specialized code for getting the length of strings and
871 // string wrapper objects. The length property of string wrapper
872 // objects is read-only and therefore always returns the length of
873 // the underlying string value. See ECMA-262 15.5.5.1.
874 if ((object->IsString() || object->IsStringWrapper()) &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000875 name->Equals(isolate()->heap()->length_string())) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000876 Handle<Code> stub;
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000877 if (state == UNINITIALIZED) {
878 stub = pre_monomorphic_stub();
879 } else if (state == PREMONOMORPHIC) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000880 StringLengthStub string_length_stub(kind(), !object->IsString());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000881 stub = string_length_stub.GetCode(isolate());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000882 } else if (state == MONOMORPHIC && object->IsStringWrapper()) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000883 StringLengthStub string_length_stub(kind(), true);
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000884 stub = string_length_stub.GetCode(isolate());
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000885 } else if (state != MEGAMORPHIC) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000886 ASSERT(state != GENERIC);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000887 stub = megamorphic_stub();
888 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000889 if (!stub.is_null()) {
890 set_target(*stub);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000891#ifdef DEBUG
892 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
893#endif
ager@chromium.org378b34e2011-01-28 08:04:38 +0000894 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000895 // Get the string if we have a string wrapper object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000896 Handle<Object> string = object->IsJSValue()
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000897 ? Handle<Object>(Handle<JSValue>::cast(object)->value(), isolate())
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000898 : object;
899 return Smi::FromInt(String::cast(*string)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000900 }
901
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902 // Use specialized code for getting prototype of functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000903 if (object->IsJSFunction() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000904 name->Equals(isolate()->heap()->prototype_string()) &&
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000905 Handle<JSFunction>::cast(object)->should_have_prototype()) {
906 Handle<Code> stub;
907 if (state == UNINITIALIZED) {
908 stub = pre_monomorphic_stub();
909 } else if (state == PREMONOMORPHIC) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000910 FunctionPrototypeStub function_prototype_stub(kind());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000911 stub = function_prototype_stub.GetCode(isolate());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000912 } else if (state != MEGAMORPHIC) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000913 ASSERT(state != GENERIC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000914 stub = megamorphic_stub();
915 }
916 if (!stub.is_null()) {
917 set_target(*stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000918#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000919 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000920#endif
ager@chromium.org378b34e2011-01-28 08:04:38 +0000921 }
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000922 return *Accessors::FunctionGetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923 }
924 }
925
926 // Check if the name is trivially convertible to an index and get
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000927 // the element or char if so.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000928 uint32_t index;
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000929 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
930 // Rewrite to the generic keyed load stub.
931 if (FLAG_use_ic) set_target(*generic_stub());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000932 return Runtime::GetElementOrCharAtOrFail(isolate(), object, index);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +0000933 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934
danno@chromium.orgf005df62013-04-30 16:36:45 +0000935 if (object->IsJSObject()) {
936 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
937 if (receiver->map()->is_deprecated()) {
938 JSObject::MigrateInstance(receiver);
939 }
940 }
941
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942 // Named lookup in the object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000943 LookupResult lookup(isolate());
944 LookupForRead(object, name, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000945
ager@chromium.org5c838252010-02-19 08:53:10 +0000946 // If we did not find a property, check if we need to throw an exception.
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000947 if (!lookup.IsFound()) {
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +0000948 if (IsUndeclaredGlobal(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000949 return ReferenceError("not_defined", name);
950 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000951 LOG(isolate(), SuspectReadEvent(*name, *object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000952 }
953
954 // Update inline cache and stub cache.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000955 if (FLAG_use_ic) UpdateCaches(&lookup, state, object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000956
957 PropertyAttributes attr;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000958 if (lookup.IsInterceptor() || lookup.IsHandler()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959 // Get the property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000960 Handle<Object> result =
961 Object::GetProperty(object, object, &lookup, name, &attr);
962 RETURN_IF_EMPTY_HANDLE(isolate(), result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000963 // If the property is not present, check if we need to throw an
964 // exception.
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +0000965 if (attr == ABSENT && IsUndeclaredGlobal(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000966 return ReferenceError("not_defined", name);
967 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000968 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000969 }
970
971 // Get the property.
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000972 return Object::GetPropertyOrFail(object, object, &lookup, name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000973}
974
975
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000976static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
977 Handle<Map> new_receiver_map) {
978 ASSERT(!new_receiver_map.is_null());
979 for (int current = 0; current < receiver_maps->length(); ++current) {
980 if (!receiver_maps->at(current).is_null() &&
981 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
982 return false;
983 }
984 }
985 receiver_maps->Add(new_receiver_map);
986 return true;
987}
988
989
990bool IC::UpdatePolymorphicIC(State state,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000991 Handle<JSObject> receiver,
992 Handle<String> name,
danno@chromium.orgbee51992013-07-10 14:57:15 +0000993 Handle<Code> code,
994 StrictModeFlag strict_mode) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000995 if (code->type() == Code::NORMAL) return false;
996 if (target()->ic_state() == MONOMORPHIC &&
997 target()->type() == Code::NORMAL) {
998 return false;
999 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001000
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001001 MapHandleList receiver_maps;
1002 CodeHandleList handlers;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001003
danno@chromium.orgf005df62013-04-30 16:36:45 +00001004 int number_of_valid_maps;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001005 int handler_to_overwrite = -1;
1006 Handle<Map> new_receiver_map(receiver->map());
ulan@chromium.org750145a2013-03-07 15:14:13 +00001007 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001008 DisallowHeapAllocation no_gc;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001009 target()->FindAllMaps(&receiver_maps);
1010 int number_of_maps = receiver_maps.length();
danno@chromium.orgf005df62013-04-30 16:36:45 +00001011 number_of_valid_maps = number_of_maps;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001012
danno@chromium.orgf005df62013-04-30 16:36:45 +00001013 for (int i = 0; i < number_of_maps; i++) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001014 Handle<Map> map = receiver_maps.at(i);
1015 // Filter out deprecated maps to ensure its instances get migrated.
1016 if (map->is_deprecated()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00001017 number_of_valid_maps--;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001018 // If the receiver map is already in the polymorphic IC, this indicates
1019 // there was a prototoype chain failure. In that case, just overwrite the
1020 // handler.
1021 } else if (map.is_identical_to(new_receiver_map)) {
1022 number_of_valid_maps--;
1023 handler_to_overwrite = i;
danno@chromium.orgf005df62013-04-30 16:36:45 +00001024 }
1025 }
1026
1027 if (number_of_valid_maps >= 4) return false;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001028
1029 // Only allow 0 maps in case target() was reset to UNINITIALIZED by the GC.
1030 // In that case, allow the IC to go back monomorphic.
1031 if (number_of_maps == 0 && target()->ic_state() != UNINITIALIZED) {
1032 return false;
1033 }
1034 target()->FindAllCode(&handlers, receiver_maps.length());
1035 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001036
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001037 number_of_valid_maps++;
1038 if (handler_to_overwrite >= 0) {
1039 handlers.Set(handler_to_overwrite, code);
1040 } else {
1041 receiver_maps.Add(new_receiver_map);
1042 handlers.Add(code);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001043 }
1044
danno@chromium.orgbee51992013-07-10 14:57:15 +00001045 Handle<Code> ic = ComputePolymorphicIC(
1046 &receiver_maps, &handlers, number_of_valid_maps, name, strict_mode);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001047 set_target(*ic);
1048 return true;
1049}
1050
1051
danno@chromium.orgbee51992013-07-10 14:57:15 +00001052Handle<Code> LoadIC::ComputePolymorphicIC(MapHandleList* receiver_maps,
1053 CodeHandleList* handlers,
1054 int number_of_valid_maps,
1055 Handle<Name> name,
1056 StrictModeFlag strict_mode) {
1057 return isolate()->stub_cache()->ComputePolymorphicLoadIC(
1058 receiver_maps, handlers, number_of_valid_maps, name);
1059}
1060
1061
1062Handle<Code> StoreIC::ComputePolymorphicIC(MapHandleList* receiver_maps,
1063 CodeHandleList* handlers,
1064 int number_of_valid_maps,
1065 Handle<Name> name,
1066 StrictModeFlag strict_mode) {
1067 return isolate()->stub_cache()->ComputePolymorphicStoreIC(
1068 receiver_maps, handlers, number_of_valid_maps, name, strict_mode);
1069}
1070
1071
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001072void LoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
1073 Handle<Code> handler,
danno@chromium.orgbee51992013-07-10 14:57:15 +00001074 Handle<String> name,
1075 StrictModeFlag strict_mode) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001076 if (handler->type() == Code::NORMAL) return set_target(*handler);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001077 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicLoadIC(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001078 receiver, handler, name);
1079 set_target(*ic);
1080}
1081
1082
1083void KeyedLoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
1084 Handle<Code> handler,
danno@chromium.orgbee51992013-07-10 14:57:15 +00001085 Handle<String> name,
1086 StrictModeFlag strict_mode) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001087 if (handler->type() == Code::NORMAL) return set_target(*handler);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001088 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicKeyedLoadIC(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001089 receiver, handler, name);
1090 set_target(*ic);
1091}
1092
1093
danno@chromium.orgbee51992013-07-10 14:57:15 +00001094void StoreIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
1095 Handle<Code> handler,
1096 Handle<String> name,
1097 StrictModeFlag strict_mode) {
1098 if (handler->type() == Code::NORMAL) return set_target(*handler);
1099 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicStoreIC(
1100 receiver, handler, name, strict_mode);
1101 set_target(*ic);
1102}
1103
1104
1105void KeyedStoreIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
1106 Handle<Code> handler,
1107 Handle<String> name,
1108 StrictModeFlag strict_mode) {
1109 if (handler->type() == Code::NORMAL) return set_target(*handler);
1110 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicKeyedStoreIC(
1111 receiver, handler, name, strict_mode);
1112 set_target(*ic);
1113}
1114
1115
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001116void IC::CopyICToMegamorphicCache(Handle<String> name) {
1117 MapHandleList receiver_maps;
1118 CodeHandleList handlers;
1119 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001120 DisallowHeapAllocation no_gc;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001121 target()->FindAllMaps(&receiver_maps);
1122 target()->FindAllCode(&handlers, receiver_maps.length());
1123 }
1124 for (int i = 0; i < receiver_maps.length(); i++) {
1125 UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i));
1126 }
1127}
1128
1129
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001130bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001131 DisallowHeapAllocation no_allocation;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001132
1133 Map* current_map = target()->FindFirstMap();
1134 ElementsKind receiver_elements_kind = receiver_map->elements_kind();
1135 bool more_general_transition =
1136 IsMoreGeneralElementsKindTransition(
1137 current_map->elements_kind(), receiver_elements_kind);
1138 Map* transitioned_map = more_general_transition
1139 ? current_map->LookupElementsTransitionMap(receiver_elements_kind)
1140 : NULL;
1141
1142 return transitioned_map == receiver_map;
1143}
1144
1145
ulan@chromium.org750145a2013-03-07 15:14:13 +00001146// Since GC may have been invoked, by the time PatchCache is called, |state| is
1147// not necessarily equal to target()->state().
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001148void IC::PatchCache(State state,
1149 StrictModeFlag strict_mode,
1150 Handle<JSObject> receiver,
1151 Handle<String> name,
1152 Handle<Code> code) {
1153 switch (state) {
1154 case UNINITIALIZED:
1155 case PREMONOMORPHIC:
1156 case MONOMORPHIC_PROTOTYPE_FAILURE:
danno@chromium.orgbee51992013-07-10 14:57:15 +00001157 UpdateMonomorphicIC(receiver, code, name, strict_mode);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001158 break;
1159 case MONOMORPHIC:
1160 // Only move to megamorphic if the target changes.
1161 if (target() != *code) {
danno@chromium.orgbee51992013-07-10 14:57:15 +00001162 if (target()->is_load_stub() || target()->is_store_stub()) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001163 bool is_same_handler = false;
1164 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001165 DisallowHeapAllocation no_allocation;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001166 Code* old_handler = target()->FindFirstCode();
1167 is_same_handler = old_handler == *code;
1168 }
1169 if (is_same_handler
1170 && IsTransitionedMapOfMonomorphicTarget(receiver->map())) {
danno@chromium.orgbee51992013-07-10 14:57:15 +00001171 UpdateMonomorphicIC(receiver, code, name, strict_mode);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001172 break;
1173 }
danno@chromium.orgbee51992013-07-10 14:57:15 +00001174 if (UpdatePolymorphicIC(state, receiver, name, code, strict_mode)) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001175 break;
1176 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001177
1178 if (target()->type() != Code::NORMAL) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001179 CopyICToMegamorphicCache(name);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001180 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001181 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001182
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001183 UpdateMegamorphicCache(receiver->map(), *name, *code);
1184 set_target((strict_mode == kStrictMode)
1185 ? *megamorphic_stub_strict()
1186 : *megamorphic_stub());
1187 }
1188 break;
1189 case MEGAMORPHIC:
1190 // Update the stub cache.
1191 UpdateMegamorphicCache(receiver->map(), *name, *code);
1192 break;
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001193 case POLYMORPHIC:
danno@chromium.orgbee51992013-07-10 14:57:15 +00001194 if (target()->is_load_stub() || target()->is_store_stub()) {
1195 if (UpdatePolymorphicIC(state, receiver, name, code, strict_mode)) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001196 break;
1197 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001198 CopyICToMegamorphicCache(name);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001199 UpdateMegamorphicCache(receiver->map(), *name, *code);
danno@chromium.orgbee51992013-07-10 14:57:15 +00001200 set_target((strict_mode == kStrictMode)
1201 ? *megamorphic_stub_strict()
1202 : *megamorphic_stub());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001203 } else {
1204 // When trying to patch a polymorphic keyed load/store element stub
1205 // with anything other than another polymorphic stub, go generic.
1206 set_target((strict_mode == kStrictMode)
1207 ? *generic_stub_strict()
1208 : *generic_stub());
1209 }
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001210 break;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001211 case DEBUG_STUB:
1212 break;
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001213 case GENERIC:
1214 UNREACHABLE();
1215 break;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001216 }
1217}
1218
1219
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001220static void GetReceiverMapsForStub(Handle<Code> stub,
1221 MapHandleList* result) {
1222 ASSERT(stub->is_inline_cache_stub());
1223 switch (stub->ic_state()) {
1224 case MONOMORPHIC: {
1225 Map* map = stub->FindFirstMap();
1226 if (map != NULL) {
1227 result->Add(Handle<Map>(map));
1228 }
1229 break;
1230 }
1231 case POLYMORPHIC: {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001232 DisallowHeapAllocation no_allocation;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001233 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
1234 for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
1235 RelocInfo* info = it.rinfo();
1236 Handle<Object> object(info->target_object(), stub->GetIsolate());
1237 if (object->IsString()) break;
1238 ASSERT(object->IsMap());
1239 AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
1240 }
1241 break;
1242 }
1243 case MEGAMORPHIC:
1244 break;
1245 case UNINITIALIZED:
1246 case PREMONOMORPHIC:
1247 case MONOMORPHIC_PROTOTYPE_FAILURE:
1248 case GENERIC:
1249 case DEBUG_STUB:
1250 UNREACHABLE();
1251 break;
1252 }
1253}
1254
1255
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001256void LoadIC::UpdateCaches(LookupResult* lookup,
1257 State state,
1258 Handle<Object> object,
1259 Handle<String> name) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001260 // Bail out if the result is not cacheable.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001261 if (!lookup->IsCacheable()) {
1262 set_target(*generic_stub());
1263 return;
1264 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001266 // TODO(jkummerow): It would be nice to support non-JSObjects in
1267 // UpdateCaches, then we wouldn't need to go generic here.
1268 if (!object->IsJSObject()) {
1269 set_target(*generic_stub());
1270 return;
1271 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001272
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001273 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001274 Handle<Code> code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001275 if (state == UNINITIALIZED) {
1276 // This is the first time we execute this inline cache.
1277 // Set the target to the pre monomorphic stub to delay
1278 // setting the monomorphic state.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001279 code = pre_monomorphic_stub();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001281 code = ComputeLoadHandler(lookup, receiver, name);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001282 if (code.is_null()) {
1283 set_target(*generic_stub());
1284 return;
1285 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 }
1287
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001288 PatchCache(state, kNonStrictMode, receiver, name, code);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001289 TRACE_IC("LoadIC", name, state, target());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290}
1291
1292
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001293void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001294 // Cache code holding map should be consistent with
1295 // GenerateMonomorphicCacheProbe.
1296 isolate()->stub_cache()->Set(name, map, code);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001297}
1298
1299
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001300Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
1301 Handle<JSObject> receiver,
1302 Handle<String> name) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001303 if (!lookup->IsProperty()) {
1304 // Nonexistent property. The result is undefined.
1305 return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001306 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001307
1308 // Compute monomorphic stub.
1309 Handle<JSObject> holder(lookup->holder());
1310 switch (lookup->type()) {
1311 case FIELD:
1312 return isolate()->stub_cache()->ComputeLoadField(
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001313 name, receiver, holder,
1314 lookup->GetFieldIndex(), lookup->representation());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001315 case CONSTANT_FUNCTION: {
1316 Handle<JSFunction> constant(lookup->GetConstantFunction());
1317 return isolate()->stub_cache()->ComputeLoadConstant(
1318 name, receiver, holder, constant);
1319 }
1320 case NORMAL:
1321 if (holder->IsGlobalObject()) {
1322 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001323 Handle<PropertyCell> cell(
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001324 global->GetPropertyCell(lookup), isolate());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001325 return isolate()->stub_cache()->ComputeLoadGlobal(
1326 name, receiver, global, cell, lookup->IsDontDelete());
1327 }
1328 // There is only one shared stub for loading normalized
1329 // properties. It does not traverse the prototype chain, so the
1330 // property must be found in the receiver for the stub to be
1331 // applicable.
1332 if (!holder.is_identical_to(receiver)) break;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001333 return isolate()->stub_cache()->ComputeLoadNormal(name, receiver);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001334 case CALLBACKS: {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001335 Handle<Object> callback(lookup->GetCallbackObject(), isolate());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001336 if (callback->IsExecutableAccessorInfo()) {
1337 Handle<ExecutableAccessorInfo> info =
1338 Handle<ExecutableAccessorInfo>::cast(callback);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001339 if (v8::ToCData<Address>(info->getter()) == 0) break;
1340 if (!info->IsCompatibleReceiver(*receiver)) break;
1341 return isolate()->stub_cache()->ComputeLoadCallback(
1342 name, receiver, holder, info);
1343 } else if (callback->IsAccessorPair()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001344 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(),
1345 isolate());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001346 if (!getter->IsJSFunction()) break;
1347 if (holder->IsGlobalObject()) break;
1348 if (!holder->HasFastProperties()) break;
1349 return isolate()->stub_cache()->ComputeLoadViaGetter(
1350 name, receiver, holder, Handle<JSFunction>::cast(getter));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001351 } else if (receiver->IsJSArray() &&
1352 name->Equals(isolate()->heap()->length_string())) {
1353 PropertyIndex lengthIndex =
1354 PropertyIndex::NewHeaderIndex(JSArray::kLengthOffset / kPointerSize);
1355 return isolate()->stub_cache()->ComputeLoadField(
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001356 name, receiver, holder, lengthIndex, Representation::Tagged());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001357 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001358 // TODO(dcarney): Handle correctly.
1359 if (callback->IsDeclaredAccessorInfo()) break;
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001360 ASSERT(callback->IsForeign());
1361 // No IC support for old-style native accessors.
1362 break;
1363 }
1364 case INTERCEPTOR:
1365 ASSERT(HasInterceptorGetter(*holder));
1366 return isolate()->stub_cache()->ComputeLoadInterceptor(
1367 name, receiver, holder);
1368 default:
1369 break;
1370 }
1371 return Handle<Code>::null();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001372}
1373
1374
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001375static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
1376 // This helper implements a few common fast cases for converting
1377 // non-smi keys of keyed loads/stores to a smi or a string.
1378 if (key->IsHeapNumber()) {
1379 double value = Handle<HeapNumber>::cast(key)->value();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001380 if (std::isnan(value)) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001381 key = isolate->factory()->nan_string();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001382 } else {
1383 int int_value = FastD2I(value);
1384 if (value == int_value && Smi::IsValid(int_value)) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001385 key = Handle<Smi>(Smi::FromInt(int_value), isolate);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001386 }
1387 }
1388 } else if (key->IsUndefined()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001389 key = isolate->factory()->undefined_string();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001390 }
1391 return key;
1392}
1393
1394
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001395Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
1396 State ic_state = target()->ic_state();
1397
1398 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1399 // via megamorphic stubs, since they don't have a map in their relocation info
1400 // and so the stubs can't be harvested for the object needed for a map check.
1401 if (target()->type() != Code::NORMAL) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001402 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type");
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001403 return generic_stub();
1404 }
1405
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001406 Handle<Map> receiver_map(receiver->map(), isolate());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001407 MapHandleList target_receiver_maps;
1408 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
1409 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
1410 // yet will do so and stay there.
1411 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1412 }
1413
1414 if (target() == *string_stub()) {
1415 target_receiver_maps.Add(isolate()->factory()->string_map());
1416 } else {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001417 GetReceiverMapsForStub(Handle<Code>(target(), isolate()),
1418 &target_receiver_maps);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001419 if (target_receiver_maps.length() == 0) {
1420 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1421 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001422 }
1423
1424 // The first time a receiver is seen that is a transitioned version of the
1425 // previous monomorphic receiver type, assume the new ElementsKind is the
1426 // monomorphic type. This benefits global arrays that only transition
1427 // once, and all call sites accessing them are faster if they remain
1428 // monomorphic. If this optimistic assumption is not true, the IC will
1429 // miss again and it will become polymorphic and support both the
1430 // untransitioned and transitioned maps.
1431 if (ic_state == MONOMORPHIC &&
1432 IsMoreGeneralElementsKindTransition(
1433 target_receiver_maps.at(0)->elements_kind(),
1434 receiver->GetElementsKind())) {
1435 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
1436 }
1437
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001438 ASSERT(ic_state != GENERIC);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001439
1440 // Determine the list of receiver maps that this call site has seen,
1441 // adding the map that was just encountered.
1442 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
1443 // If the miss wasn't due to an unseen map, a polymorphic stub
1444 // won't help, use the generic stub.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001445 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice");
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001446 return generic_stub();
1447 }
1448
1449 // If the maximum number of receiver maps has been exceeded, use the generic
1450 // version of the IC.
1451 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001452 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded");
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001453 return generic_stub();
1454 }
1455
1456 return isolate()->stub_cache()->ComputeLoadElementPolymorphic(
1457 &target_receiver_maps);
1458}
1459
1460
lrn@chromium.org303ada72010-10-27 09:33:13 +00001461MaybeObject* KeyedLoadIC::Load(State state,
1462 Handle<Object> object,
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001463 Handle<Object> key,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001464 ICMissMode miss_mode) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001465 // Check for values that can be converted into an internalized string directly
1466 // or is representable as a smi.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001467 key = TryConvertKey(key, isolate());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001468
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001469 if (key->IsInternalizedString()) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001470 return LoadIC::Load(state, object, Handle<String>::cast(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 }
1472
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001474 ASSERT(!(use_ic && object->IsJSGlobalProxy()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001476 if (use_ic) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001477 Handle<Code> stub = generic_stub();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001478 if (miss_mode != MISS_FORCE_GENERIC) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001479 if (object->IsString() && key->IsNumber()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001480 if (state == UNINITIALIZED) {
1481 stub = string_stub();
1482 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001483 } else if (object->IsJSObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001484 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001485 if (receiver->map()->is_deprecated()) {
1486 JSObject::MigrateInstance(receiver);
1487 }
1488
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001489 if (receiver->elements()->map() ==
1490 isolate()->heap()->non_strict_arguments_elements_map()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001491 stub = non_strict_arguments_stub();
1492 } else if (receiver->HasIndexedInterceptor()) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001493 stub = indexed_interceptor_stub();
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001494 } else if (!key->ToSmi()->IsFailure() &&
1495 (target() != *non_strict_arguments_stub())) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001496 stub = LoadElementStub(receiver);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001497 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001498 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001499 } else {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001500 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "force generic");
ager@chromium.org3811b432009-10-28 14:53:37 +00001501 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001502 ASSERT(!stub.is_null());
1503 set_target(*stub);
1504 TRACE_IC("KeyedLoadIC", key, state, target());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001505 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001506
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00001508 return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509}
1510
1511
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001512Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup,
1513 Handle<JSObject> receiver,
1514 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 // Bail out if we didn't find a result.
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001516 if (!lookup->IsProperty()) return Handle<Code>::null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001517
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001518 // Compute a monomorphic stub.
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001519 Handle<JSObject> holder(lookup->holder(), isolate());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001520 switch (lookup->type()) {
1521 case FIELD:
1522 return isolate()->stub_cache()->ComputeKeyedLoadField(
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001523 name, receiver, holder,
1524 lookup->GetFieldIndex(), lookup->representation());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001525 case CONSTANT_FUNCTION: {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001526 Handle<JSFunction> constant(lookup->GetConstantFunction(), isolate());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001527 return isolate()->stub_cache()->ComputeKeyedLoadConstant(
1528 name, receiver, holder, constant);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001530 case CALLBACKS: {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001531 Handle<Object> callback_object(lookup->GetCallbackObject(), isolate());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001532 // TODO(dcarney): Handle DeclaredAccessorInfo correctly.
1533 if (!callback_object->IsExecutableAccessorInfo()) break;
1534 Handle<ExecutableAccessorInfo> callback =
1535 Handle<ExecutableAccessorInfo>::cast(callback_object);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001536 if (v8::ToCData<Address>(callback->getter()) == 0) break;
1537 if (!callback->IsCompatibleReceiver(*receiver)) break;
1538 return isolate()->stub_cache()->ComputeKeyedLoadCallback(
1539 name, receiver, holder, callback);
1540 }
1541 case INTERCEPTOR:
1542 ASSERT(HasInterceptorGetter(lookup->holder()));
1543 return isolate()->stub_cache()->ComputeKeyedLoadInterceptor(
1544 name, receiver, holder);
1545 default:
1546 // Always rewrite to the generic case so that we do not
1547 // repeatedly try to rewrite.
1548 return generic_stub();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001550 return Handle<Code>::null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001551}
1552
1553
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001554static bool LookupForWrite(Handle<JSObject> receiver,
1555 Handle<String> name,
danno@chromium.orgf005df62013-04-30 16:36:45 +00001556 Handle<Object> value,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001557 LookupResult* lookup,
1558 IC::State* state) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001559 Handle<JSObject> holder = receiver;
1560 receiver->Lookup(*name, lookup);
1561 if (lookup->IsFound()) {
1562 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
1563
1564 if (lookup->holder() == *receiver) {
1565 if (lookup->IsInterceptor() &&
1566 receiver->GetNamedInterceptor()->setter()->IsUndefined()) {
1567 receiver->LocalLookupRealNamedProperty(*name, lookup);
1568 return lookup->IsFound() &&
1569 !lookup->IsReadOnly() &&
danno@chromium.orgf005df62013-04-30 16:36:45 +00001570 lookup->CanHoldValue(value) &&
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001571 lookup->IsCacheable();
1572 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00001573 return lookup->CanHoldValue(value);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001574 }
1575
1576 if (lookup->IsPropertyCallbacks()) return true;
1577
1578 // Currently normal holders in the prototype chain are not supported. They
1579 // would require a runtime positive lookup and verification that the details
1580 // have not changed.
1581 if (lookup->IsInterceptor() || lookup->IsNormal()) return false;
1582 holder = Handle<JSObject>(lookup->holder(), lookup->isolate());
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001583 }
1584
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001585 // While normally LookupTransition gets passed the receiver, in this case we
1586 // pass the holder of the property that we overwrite. This keeps the holder in
1587 // the LookupResult intact so we can later use it to generate a prototype
1588 // chain check. This avoids a double lookup, but requires us to pass in the
1589 // receiver when trying to fetch extra information from the transition.
1590 receiver->map()->LookupTransition(*holder, *name, lookup);
danno@chromium.orgf005df62013-04-30 16:36:45 +00001591 if (!lookup->IsTransition()) return false;
1592 PropertyDetails target_details =
1593 lookup->GetTransitionDetails(receiver->map());
1594 if (target_details.IsReadOnly()) return false;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001595
1596 // If the value that's being stored does not fit in the field that the
1597 // instance would transition to, create a new transition that fits the value.
1598 // This has to be done before generating the IC, since that IC will embed the
1599 // transition target.
1600 // Ensure the instance and its map were migrated before trying to update the
1601 // transition target.
1602 ASSERT(!receiver->map()->is_deprecated());
1603 if (!value->FitsRepresentation(target_details.representation())) {
1604 Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map()));
1605 Map::GeneralizeRepresentation(
1606 target, target->LastAdded(), value->OptimalRepresentation());
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001607 // Lookup the transition again since the transition tree may have changed
1608 // entirely by the migration above.
1609 receiver->map()->LookupTransition(*holder, *name, lookup);
1610 if (!lookup->IsTransition()) return false;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001611 *state = MONOMORPHIC_PROTOTYPE_FAILURE;
1612 }
1613 return true;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001614}
1615
1616
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001617MaybeObject* StoreIC::Store(State state,
1618 StrictModeFlag strict_mode,
1619 Handle<Object> object,
1620 Handle<String> name,
1621 Handle<Object> value,
1622 JSReceiver::StoreFromKeyed store_mode) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001623 // Handle proxies.
1624 if (object->IsJSProxy()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001625 return JSReceiver::SetPropertyOrFail(
1626 Handle<JSReceiver>::cast(object), name, value, NONE, strict_mode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001627 }
1628
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001629 // If the object is undefined or null it's illegal to try to set any
1630 // properties on it; throw a TypeError in that case.
1631 if (object->IsUndefined() || object->IsNull()) {
1632 return TypeError("non_object_property_store", object, name);
1633 }
1634
1635 // The length property of string values is read-only. Throw in strict mode.
1636 if (strict_mode == kStrictMode && object->IsString() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001637 name->Equals(isolate()->heap()->length_string())) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001638 return TypeError("strict_read_only_property", object, name);
1639 }
1640
1641 // Ignore other stores where the receiver is not a JSObject.
1642 // TODO(1475): Must check prototype chains of object wrappers.
1643 if (!object->IsJSObject()) return *value;
1644
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1646
danno@chromium.orgf005df62013-04-30 16:36:45 +00001647 if (receiver->map()->is_deprecated()) {
1648 JSObject::MigrateInstance(receiver);
1649 }
1650
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651 // Check if the given name is an array index.
1652 uint32_t index;
1653 if (name->AsArrayIndex(&index)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001654 Handle<Object> result =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001655 JSObject::SetElement(receiver, index, value, NONE, strict_mode);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001656 RETURN_IF_EMPTY_HANDLE(isolate(), result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001657 return *value;
1658 }
1659
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001660 // Observed objects are always modified through the runtime.
1661 if (FLAG_harmony_observation && receiver->map()->is_observed()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001662 return JSReceiver::SetPropertyOrFail(
1663 receiver, name, value, NONE, strict_mode, store_mode);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001664 }
1665
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001666 // Use specialized code for setting the length of arrays with fast
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001667 // properties. Slow properties might indicate redefinition of the length
danno@chromium.org1bc70ab2013-07-14 22:07:11 +00001668 // property. Note that when redefined using Object.freeze, it's possible
1669 // to have fast properties but a read-only length.
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001670 if (FLAG_use_ic &&
1671 receiver->IsJSArray() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001672 name->Equals(isolate()->heap()->length_string()) &&
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001673 Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() &&
danno@chromium.org1bc70ab2013-07-14 22:07:11 +00001674 receiver->HasFastProperties() &&
1675 !receiver->map()->is_frozen()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001676 Handle<Code> stub =
1677 StoreArrayLengthStub(kind(), strict_mode).GetCode(isolate());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001678 set_target(*stub);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001679 TRACE_IC("StoreIC", name, state, *stub);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001680 return JSReceiver::SetPropertyOrFail(
1681 receiver, name, value, NONE, strict_mode, store_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682 }
1683
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001684 if (receiver->IsJSGlobalProxy()) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001685 if (FLAG_use_ic && kind() != Code::KEYED_STORE_IC) {
1686 // Generate a generic stub that goes to the runtime when we see a global
1687 // proxy as receiver.
1688 Handle<Code> stub = (strict_mode == kStrictMode)
1689 ? global_proxy_stub_strict()
1690 : global_proxy_stub();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001691 set_target(*stub);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001692 TRACE_IC("StoreIC", name, state, *stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001693 }
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001694 return JSReceiver::SetPropertyOrFail(
1695 receiver, name, value, NONE, strict_mode, store_mode);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001696 }
1697
1698 LookupResult lookup(isolate());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001699 if (LookupForWrite(receiver, name, value, &lookup, &state)) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001700 if (FLAG_use_ic) {
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001701 UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001702 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001703 } else if (strict_mode == kStrictMode &&
1704 !(lookup.IsProperty() && lookup.IsReadOnly()) &&
1705 IsUndeclaredGlobal(object)) {
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00001706 // Strict mode doesn't allow setting non-existent global property.
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001707 return ReferenceError("not_defined", name);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001708 } else if (FLAG_use_ic &&
1709 (lookup.IsNormal() ||
1710 (lookup.IsField() && lookup.CanHoldValue(value)))) {
1711 Handle<Code> stub = strict_mode == kStrictMode
1712 ? generic_stub_strict() : generic_stub();
1713 set_target(*stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001714 }
1715
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001716 // Set the property.
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001717 return JSReceiver::SetPropertyOrFail(
1718 receiver, name, value, NONE, strict_mode, store_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719}
1720
1721
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001722void StoreIC::UpdateCaches(LookupResult* lookup,
1723 State state,
1724 StrictModeFlag strict_mode,
1725 Handle<JSObject> receiver,
1726 Handle<String> name,
1727 Handle<Object> value) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001728 ASSERT(!receiver->IsJSGlobalProxy());
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001729 ASSERT(lookup->IsFound());
1730
danno@chromium.orgc612e022011-11-10 11:38:15 +00001731 // These are not cacheable, so we never see such LookupResults here.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001732 ASSERT(!lookup->IsHandler());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001734 Handle<Code> code = ComputeStoreMonomorphic(
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001735 lookup, strict_mode, receiver, name, value);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001736 if (code.is_null()) {
1737 Handle<Code> stub = strict_mode == kStrictMode
1738 ? generic_stub_strict() : generic_stub();
1739 set_target(*stub);
1740 return;
1741 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001742
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001743 PatchCache(state, strict_mode, receiver, name, code);
1744 TRACE_IC("StoreIC", name, state, target());
1745}
1746
1747
1748Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
1749 StrictModeFlag strict_mode,
1750 Handle<JSObject> receiver,
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001751 Handle<String> name,
1752 Handle<Object> value) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001753 Handle<JSObject> holder(lookup->holder());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001754 switch (lookup->type()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001755 case FIELD:
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001756 return isolate()->stub_cache()->ComputeStoreField(
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001757 name, receiver, lookup, strict_mode);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001758 case NORMAL:
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001759 if (receiver->IsGlobalObject()) {
1760 // The stub generated for the global object picks the value directly
1761 // from the property cell. So the property must be directly on the
1762 // global object.
1763 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001764 Handle<PropertyCell> cell(
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001765 global->GetPropertyCell(lookup), isolate());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001766 return isolate()->stub_cache()->ComputeStoreGlobal(
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001767 name, global, cell, value, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001768 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001769 ASSERT(holder.is_identical_to(receiver));
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001770 return isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001771 case CALLBACKS: {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001772 Handle<Object> callback(lookup->GetCallbackObject(), isolate());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001773 if (callback->IsExecutableAccessorInfo()) {
1774 Handle<ExecutableAccessorInfo> info =
1775 Handle<ExecutableAccessorInfo>::cast(callback);
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001776 if (v8::ToCData<Address>(info->setter()) == 0) break;
1777 if (!holder->HasFastProperties()) break;
1778 if (!info->IsCompatibleReceiver(*receiver)) break;
1779 return isolate()->stub_cache()->ComputeStoreCallback(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001780 name, receiver, holder, info, strict_mode);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001781 } else if (callback->IsAccessorPair()) {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001782 Handle<Object> setter(
1783 Handle<AccessorPair>::cast(callback)->setter(), isolate());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001784 if (!setter->IsJSFunction()) break;
1785 if (holder->IsGlobalObject()) break;
1786 if (!holder->HasFastProperties()) break;
1787 return isolate()->stub_cache()->ComputeStoreViaSetter(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00001788 name, receiver, holder, Handle<JSFunction>::cast(setter),
1789 strict_mode);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001790 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001791 // TODO(dcarney): Handle correctly.
1792 if (callback->IsDeclaredAccessorInfo()) break;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001793 ASSERT(callback->IsForeign());
1794 // No IC support for old-style native accessors.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001795 break;
1796 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001797 case INTERCEPTOR:
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001798 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001799 return isolate()->stub_cache()->ComputeStoreInterceptor(
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001800 name, receiver, strict_mode);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001801 case CONSTANT_FUNCTION:
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001802 break;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001803 case TRANSITION: {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001804 // Explicitly pass in the receiver map since LookupForWrite may have
1805 // stored something else than the receiver in the holder.
1806 Handle<Map> transition(
1807 lookup->GetTransitionTarget(receiver->map()), isolate());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001808 int descriptor = transition->LastAdded();
1809
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001810 DescriptorArray* target_descriptors = transition->instance_descriptors();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001811 PropertyDetails details = target_descriptors->GetDetails(descriptor);
1812
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001813 if (details.type() == CALLBACKS || details.attributes() != NONE) break;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001814
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001815 return isolate()->stub_cache()->ComputeStoreTransition(
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001816 name, receiver, lookup, transition, strict_mode);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001817 }
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001818 case NONEXISTENT:
danno@chromium.orgc612e022011-11-10 11:38:15 +00001819 case HANDLER:
danno@chromium.orgc612e022011-11-10 11:38:15 +00001820 UNREACHABLE();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001821 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001822 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001823 return Handle<Code>::null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001824}
1825
1826
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001827Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001828 KeyedAccessStoreMode store_mode,
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001829 StrictModeFlag strict_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001830 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1831 // via megamorphic stubs, since they don't have a map in their relocation info
1832 // and so the stubs can't be harvested for the object needed for a map check.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001833 if (target()->type() != Code::NORMAL) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001834 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type");
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001835 return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001836 }
1837
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001838 if (!FLAG_compiled_keyed_stores &&
1839 (store_mode == STORE_NO_TRANSITION_HANDLE_COW ||
ulan@chromium.org750145a2013-03-07 15:14:13 +00001840 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS)) {
1841 // TODO(danno): We'll soon handle MONOMORPHIC ICs that also support
1842 // copying COW arrays and silently ignoring some OOB stores into external
1843 // arrays, but for now use the generic.
1844 TRACE_GENERIC_IC(isolate(), "KeyedIC", "COW/OOB external array");
1845 return strict_mode == kStrictMode
1846 ? generic_stub_strict()
1847 : generic_stub();
1848 }
1849
1850 State ic_state = target()->ic_state();
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001851 Handle<Map> receiver_map(receiver->map(), isolate());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001852 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
1853 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
1854 // yet will do so and stay there.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001855 Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, store_mode);
1856 store_mode = GetNonTransitioningStoreMode(store_mode);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001857 return isolate()->stub_cache()->ComputeKeyedStoreElement(
ulan@chromium.org750145a2013-03-07 15:14:13 +00001858 monomorphic_map, strict_mode, store_mode);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001859 }
1860
ulan@chromium.org750145a2013-03-07 15:14:13 +00001861 MapHandleList target_receiver_maps;
1862 target()->FindAllMaps(&target_receiver_maps);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001863 if (target_receiver_maps.length() == 0) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001864 // In the case that there is a non-map-specific IC is installed (e.g. keyed
1865 // stores into properties in dictionary mode), then there will be not
1866 // receiver maps in the target.
1867 return strict_mode == kStrictMode
1868 ? generic_stub_strict()
1869 : generic_stub();
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001870 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001871
1872 // There are several special cases where an IC that is MONOMORPHIC can still
1873 // transition to a different GetNonTransitioningStoreMode IC that handles a
1874 // superset of the original IC. Handle those here if the receiver map hasn't
1875 // changed or it has transitioned to a more general kind.
1876 KeyedAccessStoreMode old_store_mode =
1877 Code::GetKeyedAccessStoreMode(target()->extra_ic_state());
1878 Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
danno@chromium.org169691d2013-07-15 08:01:13 +00001879 if (ic_state == MONOMORPHIC) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001880 // If the "old" and "new" maps are in the same elements map family, stay
1881 // MONOMORPHIC and use the map for the most generic ElementsKind.
1882 Handle<Map> transitioned_receiver_map = receiver_map;
1883 if (IsTransitionStoreMode(store_mode)) {
1884 transitioned_receiver_map =
1885 ComputeTransitionedMap(receiver, store_mode);
1886 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001887 if (IsTransitionedMapOfMonomorphicTarget(*transitioned_receiver_map)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001888 // Element family is the same, use the "worst" case map.
1889 store_mode = GetNonTransitioningStoreMode(store_mode);
1890 return isolate()->stub_cache()->ComputeKeyedStoreElement(
1891 transitioned_receiver_map, strict_mode, store_mode);
danno@chromium.org169691d2013-07-15 08:01:13 +00001892 } else if (*previous_receiver_map == receiver->map() &&
1893 old_store_mode == STANDARD_STORE &&
1894 (IsGrowStoreMode(store_mode) ||
1895 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
1896 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
1897 // A "normal" IC that handles stores can switch to a version that can
1898 // grow at the end of the array, handle OOB accesses or copy COW arrays
1899 // and still stay MONOMORPHIC.
1900 return isolate()->stub_cache()->ComputeKeyedStoreElement(
1901 receiver_map, strict_mode, store_mode);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001902 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001903 }
1904
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00001905 ASSERT(ic_state != GENERIC);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001906
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001907 bool map_added =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001908 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001909
ulan@chromium.org750145a2013-03-07 15:14:13 +00001910 if (IsTransitionStoreMode(store_mode)) {
1911 Handle<Map> transitioned_receiver_map =
1912 ComputeTransitionedMap(receiver, store_mode);
1913 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
1914 transitioned_receiver_map);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001915 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001916
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001917 if (!map_added) {
1918 // If the miss wasn't due to an unseen map, a polymorphic stub
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001919 // won't help, use the generic stub.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001920 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice");
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001921 return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001922 }
1923
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001924 // If the maximum number of receiver maps has been exceeded, use the generic
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001925 // version of the IC.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001926 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001927 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded");
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001928 return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001929 }
1930
ulan@chromium.org750145a2013-03-07 15:14:13 +00001931 // Make sure all polymorphic handlers have the same store mode, otherwise the
1932 // generic stub must be used.
1933 store_mode = GetNonTransitioningStoreMode(store_mode);
1934 if (old_store_mode != STANDARD_STORE) {
1935 if (store_mode == STANDARD_STORE) {
1936 store_mode = old_store_mode;
1937 } else if (store_mode != old_store_mode) {
1938 TRACE_GENERIC_IC(isolate(), "KeyedIC", "store mode mismatch");
1939 return strict_mode == kStrictMode
1940 ? generic_stub_strict()
1941 : generic_stub();
1942 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001943 }
1944
jkummerow@chromium.org91efda92013-03-25 16:32:26 +00001945 // If the store mode isn't the standard mode, make sure that all polymorphic
1946 // receivers are either external arrays, or all "normal" arrays. Otherwise,
1947 // use the generic stub.
1948 if (store_mode != STANDARD_STORE) {
1949 int external_arrays = 0;
1950 for (int i = 0; i < target_receiver_maps.length(); ++i) {
1951 if (target_receiver_maps[i]->has_external_array_elements()) {
1952 external_arrays++;
1953 }
1954 }
1955 if (external_arrays != 0 &&
1956 external_arrays != target_receiver_maps.length()) {
1957 TRACE_GENERIC_IC(isolate(), "KeyedIC",
1958 "unsupported combination of external and normal arrays");
1959 return strict_mode == kStrictMode
1960 ? generic_stub_strict()
1961 : generic_stub();
1962 }
1963 }
1964
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001965 return isolate()->stub_cache()->ComputeStoreElementPolymorphic(
ulan@chromium.org750145a2013-03-07 15:14:13 +00001966 &target_receiver_maps, store_mode, strict_mode);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001967}
1968
1969
ulan@chromium.org750145a2013-03-07 15:14:13 +00001970Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
1971 Handle<JSObject> receiver,
1972 KeyedAccessStoreMode store_mode) {
1973 switch (store_mode) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001974 case STORE_TRANSITION_SMI_TO_OBJECT:
1975 case STORE_TRANSITION_DOUBLE_TO_OBJECT:
1976 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
1977 case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001978 return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001979 case STORE_TRANSITION_SMI_TO_DOUBLE:
1980 case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001981 return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001982 case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
1983 case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
1984 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
1985 case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001986 return JSObject::GetElementsTransitionMap(receiver,
1987 FAST_HOLEY_ELEMENTS);
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001988 case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
1989 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001990 return JSObject::GetElementsTransitionMap(receiver,
1991 FAST_HOLEY_DOUBLE_ELEMENTS);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001992 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
1993 ASSERT(receiver->map()->has_external_array_elements());
1994 // Fall through
1995 case STORE_NO_TRANSITION_HANDLE_COW:
1996 case STANDARD_STORE:
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001997 case STORE_AND_GROW_NO_TRANSITION:
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001998 return Handle<Map>(receiver->map(), isolate());
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001999 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002000 return Handle<Map>::null();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002001}
2002
2003
ulan@chromium.org750145a2013-03-07 15:14:13 +00002004bool IsOutOfBoundsAccess(Handle<JSObject> receiver,
2005 int index) {
2006 if (receiver->IsJSArray()) {
2007 return JSArray::cast(*receiver)->length()->IsSmi() &&
2008 index >= Smi::cast(JSArray::cast(*receiver)->length())->value();
2009 }
2010 return index >= receiver->elements()->length();
2011}
2012
2013
2014KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
2015 Handle<Object> key,
2016 Handle<Object> value) {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002017 ASSERT(!key->ToSmi()->IsFailure());
2018 Smi* smi_key = NULL;
2019 key->ToSmi()->To(&smi_key);
2020 int index = smi_key->value();
ulan@chromium.org750145a2013-03-07 15:14:13 +00002021 bool oob_access = IsOutOfBoundsAccess(receiver, index);
2022 bool allow_growth = receiver->IsJSArray() && oob_access;
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002023 if (allow_growth) {
2024 // Handle growing array in stub if necessary.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002025 if (receiver->HasFastSmiElements()) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002026 if (value->IsHeapNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002027 if (receiver->HasFastHoleyElements()) {
2028 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE;
2029 } else {
2030 return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE;
2031 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002032 }
2033 if (value->IsHeapObject()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002034 if (receiver->HasFastHoleyElements()) {
2035 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT;
2036 } else {
2037 return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT;
2038 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002039 }
2040 } else if (receiver->HasFastDoubleElements()) {
2041 if (!value->IsSmi() && !value->IsHeapNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002042 if (receiver->HasFastHoleyElements()) {
2043 return STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
2044 } else {
2045 return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT;
2046 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002047 }
2048 }
2049 return STORE_AND_GROW_NO_TRANSITION;
2050 } else {
2051 // Handle only in-bounds elements accesses.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002052 if (receiver->HasFastSmiElements()) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002053 if (value->IsHeapNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002054 if (receiver->HasFastHoleyElements()) {
2055 return STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE;
2056 } else {
2057 return STORE_TRANSITION_SMI_TO_DOUBLE;
2058 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002059 } else if (value->IsHeapObject()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002060 if (receiver->HasFastHoleyElements()) {
2061 return STORE_TRANSITION_HOLEY_SMI_TO_OBJECT;
2062 } else {
2063 return STORE_TRANSITION_SMI_TO_OBJECT;
2064 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002065 }
2066 } else if (receiver->HasFastDoubleElements()) {
2067 if (!value->IsSmi() && !value->IsHeapNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002068 if (receiver->HasFastHoleyElements()) {
2069 return STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
2070 } else {
2071 return STORE_TRANSITION_DOUBLE_TO_OBJECT;
2072 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002073 }
2074 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00002075 if (!FLAG_trace_external_array_abuse &&
2076 receiver->map()->has_external_array_elements() && oob_access) {
2077 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002078 }
2079 Heap* heap = receiver->GetHeap();
2080 if (receiver->elements()->map() == heap->fixed_cow_array_map()) {
2081 return STORE_NO_TRANSITION_HANDLE_COW;
ulan@chromium.org750145a2013-03-07 15:14:13 +00002082 } else {
2083 return STANDARD_STORE;
2084 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002085 }
2086}
2087
2088
lrn@chromium.org303ada72010-10-27 09:33:13 +00002089MaybeObject* KeyedStoreIC::Store(State state,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002090 StrictModeFlag strict_mode,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002091 Handle<Object> object,
2092 Handle<Object> key,
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002093 Handle<Object> value,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002094 ICMissMode miss_mode) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002095 // Check for values that can be converted into an internalized string directly
2096 // or is representable as a smi.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002097 key = TryConvertKey(key, isolate());
2098
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002099 if (key->IsInternalizedString()) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00002100 return StoreIC::Store(state,
2101 strict_mode,
2102 object,
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002103 Handle<String>::cast(key),
yangguo@chromium.org003650e2013-01-24 16:31:08 +00002104 value,
2105 JSReceiver::MAY_BE_STORE_FROM_KEYED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002106 }
2107
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002108 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() &&
2109 !(FLAG_harmony_observation && object->IsJSObject() &&
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002110 JSObject::cast(*object)->map()->is_observed());
2111 if (use_ic && !object->IsSmi()) {
2112 // Don't use ICs for maps of the objects in Array's prototype chain. We
2113 // expect to be able to trap element sets to objects with those maps in the
2114 // runtime to enable optimization of element hole access.
2115 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
2116 if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false;
2117 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002118 ASSERT(!(use_ic && object->IsJSGlobalProxy()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002119
ager@chromium.org3811b432009-10-28 14:53:37 +00002120 if (use_ic) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002121 Handle<Code> stub = (strict_mode == kStrictMode)
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002122 ? generic_stub_strict()
2123 : generic_stub();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002124 if (miss_mode != MISS_FORCE_GENERIC) {
2125 if (object->IsJSObject()) {
2126 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002127 if (receiver->map()->is_deprecated()) {
2128 JSObject::MigrateInstance(receiver);
2129 }
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002130 bool key_is_smi_like = key->IsSmi() ||
2131 (FLAG_compiled_keyed_stores && !key->ToSmi()->IsFailure());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002132 if (receiver->elements()->map() ==
2133 isolate()->heap()->non_strict_arguments_elements_map()) {
2134 stub = non_strict_arguments_stub();
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002135 } else if (key_is_smi_like &&
2136 (target() != *non_strict_arguments_stub())) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002137 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value);
2138 stub = StoreElementStub(receiver, store_mode, strict_mode);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002139 } else {
2140 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "key not a number");
whesse@chromium.org7b260152011-06-20 15:33:18 +00002141 }
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002142 } else {
2143 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "not an object");
ager@chromium.org3811b432009-10-28 14:53:37 +00002144 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002145 } else {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002146 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "force generic");
ager@chromium.org3811b432009-10-28 14:53:37 +00002147 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002148 ASSERT(!stub.is_null());
2149 set_target(*stub);
2150 TRACE_IC("KeyedStoreIC", key, state, target());
ager@chromium.org3811b432009-10-28 14:53:37 +00002151 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002152
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002153 return Runtime::SetObjectPropertyOrFail(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002154 isolate(), object , key, value, NONE, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002155}
2156
2157
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002158Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
2159 StrictModeFlag strict_mode,
2160 Handle<JSObject> receiver,
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002161 Handle<String> name,
2162 Handle<Object> value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002163 // If the property has a non-field type allowing map transitions
2164 // where there is extra room in the object, we leave the IC in its
2165 // current state.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002166 switch (lookup->type()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002167 case FIELD:
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002168 return isolate()->stub_cache()->ComputeKeyedStoreField(
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002169 name, receiver, lookup, strict_mode);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002170 case TRANSITION: {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002171 // Explicitly pass in the receiver map since LookupForWrite may have
2172 // stored something else than the receiver in the holder.
2173 Handle<Map> transition(
2174 lookup->GetTransitionTarget(receiver->map()), isolate());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002175 int descriptor = transition->LastAdded();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002176
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002177 DescriptorArray* target_descriptors = transition->instance_descriptors();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002178 PropertyDetails details = target_descriptors->GetDetails(descriptor);
2179
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002180 if (details.type() != CALLBACKS && details.attributes() == NONE) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002181 return isolate()->stub_cache()->ComputeKeyedStoreTransition(
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002182 name, receiver, lookup, transition, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002183 }
2184 // fall through.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002185 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00002186 case NORMAL:
2187 case CONSTANT_FUNCTION:
2188 case CALLBACKS:
2189 case INTERCEPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190 // Always rewrite to the generic case so that we do not
2191 // repeatedly try to rewrite.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002192 return (strict_mode == kStrictMode)
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002193 ? generic_stub_strict()
2194 : generic_stub();
danno@chromium.orgc612e022011-11-10 11:38:15 +00002195 case HANDLER:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002196 case NONEXISTENT:
danno@chromium.orgc612e022011-11-10 11:38:15 +00002197 UNREACHABLE();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002198 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002199 }
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002200 return Handle<Code>::null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002201}
2202
2203
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002204#undef TRACE_IC
2205
2206
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002207// ----------------------------------------------------------------------------
2208// Static IC stub generators.
2209//
2210
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002211// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002212RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002213 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002214 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002215 CallIC ic(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002216 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002217 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2218 MaybeObject* maybe_result = ic.LoadFunction(state,
2219 extra_ic_state,
2220 args.at<Object>(0),
2221 args.at<String>(1));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002222 JSFunction* raw_function;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002223 if (!maybe_result->To(&raw_function)) return maybe_result;
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002224
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002225 // The first time the inline cache is updated may be the first time the
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002226 // function it references gets called. If the function is lazily compiled
2227 // then the first call will trigger a compilation. We check for this case
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002228 // and we do the compilation immediately, instead of waiting for the stub
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002229 // currently attached to the JSFunction object to trigger compilation.
2230 if (raw_function->is_compiled()) return raw_function;
2231
2232 Handle<JSFunction> function(raw_function);
2233 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
2234 return *function;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002235}
2236
2237
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002238// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002239RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002240 HandleScope scope(isolate);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002241 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002242 KeyedCallIC ic(isolate);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002243 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002244 MaybeObject* maybe_result =
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002245 ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002246 // Result could be a function or a failure.
2247 JSFunction* raw_function = NULL;
2248 if (!maybe_result->To(&raw_function)) return maybe_result;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002249
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002250 if (raw_function->is_compiled()) return raw_function;
2251
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002252 Handle<JSFunction> function(raw_function, isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002253 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
2254 return *function;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002255}
2256
2257
2258// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002259RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002260 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002261 ASSERT(args.length() == 2);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002262 LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002263 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002264 return ic.Load(state, args.at<Object>(0), args.at<String>(1));
2265}
2266
2267
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002268// Used from ic-<arch>.cc
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002269RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002270 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002271 ASSERT(args.length() == 2);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002272 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
2273 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
2274 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), MISS);
2275}
2276
2277
2278RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure) {
2279 HandleScope scope(isolate);
2280 ASSERT(args.length() == 2);
2281 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002282 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002283 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), MISS);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002284}
2285
2286
2287RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002288 HandleScope scope(isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002289 ASSERT(args.length() == 2);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002290 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002291 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002292 return ic.Load(state,
2293 args.at<Object>(0),
2294 args.at<Object>(1),
2295 MISS_FORCE_GENERIC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002296}
2297
2298
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002299// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002300RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002301 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002302 ASSERT(args.length() == 3);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002303 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002304 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002305 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002306 return ic.Store(state,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002307 Code::GetStrictMode(extra_ic_state),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002308 args.at<Object>(0),
2309 args.at<String>(1),
2310 args.at<Object>(2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002311}
2312
2313
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002314RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure) {
2315 HandleScope scope(isolate);
2316 ASSERT(args.length() == 3);
2317 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2318 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
2319 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2320 return ic.Store(state,
2321 Code::GetStrictMode(extra_ic_state),
2322 args.at<Object>(0),
2323 args.at<String>(1),
2324 args.at<Object>(2));
2325}
2326
2327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002328RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002329 SealHandleScope shs(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00002330
2331 ASSERT(args.length() == 2);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002332 JSArray* receiver = JSArray::cast(args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +00002333 Object* len = args[1];
2334
lrn@chromium.org303ada72010-10-27 09:33:13 +00002335 // The generated code should filter out non-Smis before we get here.
2336 ASSERT(len->IsSmi());
2337
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002338#ifdef DEBUG
2339 // The length property has to be a writable callback property.
2340 LookupResult debug_lookup(isolate);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002341 receiver->LocalLookup(isolate->heap()->length_string(), &debug_lookup);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002342 ASSERT(debug_lookup.IsPropertyCallbacks() && !debug_lookup.IsReadOnly());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002343#endif
2344
lrn@chromium.org303ada72010-10-27 09:33:13 +00002345 Object* result;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00002346 MaybeObject* maybe_result = receiver->SetElementsLength(len);
2347 if (!maybe_result->To(&result)) return maybe_result;
2348
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002349 return len;
ager@chromium.org5c838252010-02-19 08:53:10 +00002350}
2351
2352
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002353// Extend storage is called in a store inline cache when
2354// it is necessary to extend the properties array of a
2355// JSObject.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002356RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002357 SealHandleScope shs(isolate);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002358 ASSERT(args.length() == 3);
2359
2360 // Convert the parameters
2361 JSObject* object = JSObject::cast(args[0]);
2362 Map* transition = Map::cast(args[1]);
2363 Object* value = args[2];
2364
2365 // Check the object has run out out property space.
2366 ASSERT(object->HasFastProperties());
2367 ASSERT(object->map()->unused_property_fields() == 0);
2368
2369 // Expand the properties array.
2370 FixedArray* old_storage = object->properties();
2371 int new_unused = transition->unused_property_fields();
2372 int new_size = old_storage->length() + new_unused + 1;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002373 Object* result;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002374 MaybeObject* maybe_result = old_storage->CopySize(new_size);
2375 if (!maybe_result->ToObject(&result)) return maybe_result;
2376
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002377 FixedArray* new_storage = FixedArray::cast(result);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002378
2379 Object* to_store = value;
2380
2381 if (FLAG_track_double_fields) {
2382 DescriptorArray* descriptors = transition->instance_descriptors();
2383 PropertyDetails details = descriptors->GetDetails(transition->LastAdded());
2384 if (details.representation().IsDouble()) {
2385 MaybeObject* maybe_storage =
2386 isolate->heap()->AllocateHeapNumber(value->Number());
2387 if (!maybe_storage->To(&to_store)) return maybe_storage;
2388 }
2389 }
2390
2391 new_storage->set(old_storage->length(), to_store);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002392
ager@chromium.org32912102009-01-16 10:38:43 +00002393 // Set the new property value and do the map transition.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002394 object->set_properties(new_storage);
2395 object->set_map(transition);
2396
2397 // Return the stored value.
2398 return value;
2399}
2400
2401
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002402// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002403RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002404 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002405 ASSERT(args.length() == 3);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002406 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2407 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
2408 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2409 return ic.Store(state,
2410 Code::GetStrictMode(extra_ic_state),
2411 args.at<Object>(0),
2412 args.at<Object>(1),
2413 args.at<Object>(2),
2414 MISS);
2415}
2416
2417
2418RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure) {
2419 HandleScope scope(isolate);
2420 ASSERT(args.length() == 3);
2421 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002422 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002423 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2424 return ic.Store(state,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002425 Code::GetStrictMode(extra_ic_state),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002426 args.at<Object>(0),
2427 args.at<Object>(1),
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002428 args.at<Object>(2),
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002429 MISS);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002430}
2431
2432
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002433RUNTIME_FUNCTION(MaybeObject*, StoreIC_Slow) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002434 SealHandleScope shs(isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002435 ASSERT(args.length() == 3);
2436 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
2437 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2438 Handle<Object> object = args.at<Object>(0);
2439 Handle<Object> key = args.at<Object>(1);
2440 Handle<Object> value = args.at<Object>(2);
2441 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state);
2442 return Runtime::SetObjectProperty(isolate,
2443 object,
2444 key,
2445 value,
2446 NONE,
2447 strict_mode);
2448}
2449
2450
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002451RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002452 SealHandleScope shs(isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002453 ASSERT(args.length() == 3);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002454 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002455 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2456 Handle<Object> object = args.at<Object>(0);
2457 Handle<Object> key = args.at<Object>(1);
2458 Handle<Object> value = args.at<Object>(2);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002459 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002460 return Runtime::SetObjectProperty(isolate,
2461 object,
2462 key,
2463 value,
2464 NONE,
2465 strict_mode);
2466}
2467
2468
2469RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002470 HandleScope scope(isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002471 ASSERT(args.length() == 3);
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002472 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002473 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
2474 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2475 return ic.Store(state,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00002476 Code::GetStrictMode(extra_ic_state),
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002477 args.at<Object>(0),
2478 args.at<Object>(1),
2479 args.at<Object>(2),
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002480 MISS_FORCE_GENERIC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002481}
2482
2483
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00002484RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) {
2485 SealHandleScope scope(isolate);
2486 ASSERT(args.length() == 4);
2487 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
2488 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2489 Handle<Object> value = args.at<Object>(0);
2490 Handle<Object> key = args.at<Object>(2);
2491 Handle<Object> object = args.at<Object>(3);
2492 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state);
2493 return Runtime::SetObjectProperty(isolate,
2494 object,
2495 key,
2496 value,
2497 NONE,
2498 strict_mode);
2499}
2500
2501
danno@chromium.org40cb8782011-05-25 07:58:50 +00002502void BinaryOpIC::patch(Code* code) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002503 set_target(code);
2504}
2505
2506
danno@chromium.org40cb8782011-05-25 07:58:50 +00002507const char* BinaryOpIC::GetName(TypeInfo type_info) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002508 switch (type_info) {
2509 case UNINITIALIZED: return "Uninitialized";
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002510 case SMI: return "Smi";
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002511 case INT32: return "Int32";
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002512 case NUMBER: return "Number";
lrn@chromium.org7516f052011-03-30 08:52:27 +00002513 case ODDBALL: return "Oddball";
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002514 case STRING: return "String";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002515 case GENERIC: return "Generic";
2516 default: return "Invalid";
2517 }
2518}
2519
2520
danno@chromium.org40cb8782011-05-25 07:58:50 +00002521BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002522 switch (type_info) {
2523 case UNINITIALIZED:
2524 return ::v8::internal::UNINITIALIZED;
2525 case SMI:
2526 case INT32:
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002527 case NUMBER:
lrn@chromium.org7516f052011-03-30 08:52:27 +00002528 case ODDBALL:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002529 case STRING:
2530 return MONOMORPHIC;
2531 case GENERIC:
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00002532 return ::v8::internal::GENERIC;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002533 }
2534 UNREACHABLE();
2535 return ::v8::internal::UNINITIALIZED;
2536}
2537
2538
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002539Handle<Type> BinaryOpIC::TypeInfoToType(BinaryOpIC::TypeInfo binary_type,
2540 Isolate* isolate) {
2541 switch (binary_type) {
2542 case UNINITIALIZED:
2543 return handle(Type::None(), isolate);
2544 case SMI:
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002545 return handle(Type::Smi(), isolate);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002546 case INT32:
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002547 return handle(Type::Signed32(), isolate);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002548 case NUMBER:
2549 return handle(Type::Number(), isolate);
2550 case ODDBALL:
2551 return handle(Type::Optional(
2552 handle(Type::Union(
2553 handle(Type::Number(), isolate),
2554 handle(Type::String(), isolate)), isolate)), isolate);
2555 case STRING:
2556 return handle(Type::String(), isolate);
2557 case GENERIC:
2558 return handle(Type::Any(), isolate);
2559 }
2560 UNREACHABLE();
2561 return handle(Type::Any(), isolate);
2562}
2563
2564
2565void BinaryOpIC::StubInfoToType(int minor_key,
2566 Handle<Type>* left,
2567 Handle<Type>* right,
2568 Handle<Type>* result,
2569 Isolate* isolate) {
2570 TypeInfo left_typeinfo, right_typeinfo, result_typeinfo;
2571 BinaryOpStub::decode_types_from_minor_key(
2572 minor_key, &left_typeinfo, &right_typeinfo, &result_typeinfo);
2573 *left = TypeInfoToType(left_typeinfo, isolate);
2574 *right = TypeInfoToType(right_typeinfo, isolate);
2575 *result = TypeInfoToType(result_typeinfo, isolate);
2576}
2577
2578
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002579MaybeObject* UnaryOpIC::Transition(Handle<Object> object) {
2580 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
2581 UnaryOpStub stub(extra_ic_state);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002582
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002583 stub.UpdateStatus(object);
2584
2585 Handle<Code> code = stub.GetCode(isolate());
2586 set_target(*code);
2587
2588 return stub.Result(object, isolate());
2589}
2590
2591
2592RUNTIME_FUNCTION(MaybeObject*, UnaryOpIC_Miss) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002593 HandleScope scope(isolate);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002594 Handle<Object> object = args.at<Object>(0);
2595 UnaryOpIC ic(isolate);
2596 return ic.Transition(object);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002597}
2598
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002599
2600static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value,
2601 Token::Value op) {
danno@chromium.org41728482013-06-12 22:31:22 +00002602 v8::internal::TypeInfo type = v8::internal::TypeInfo::FromValue(value);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002603 if (type.IsSmi()) return BinaryOpIC::SMI;
2604 if (type.IsInteger32()) {
2605 if (kSmiValueSize == 32) return BinaryOpIC::SMI;
2606 return BinaryOpIC::INT32;
2607 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002608 if (type.IsNumber()) return BinaryOpIC::NUMBER;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002609 if (type.IsString()) return BinaryOpIC::STRING;
2610 if (value->IsUndefined()) {
2611 if (op == Token::BIT_AND ||
2612 op == Token::BIT_OR ||
2613 op == Token::BIT_XOR ||
2614 op == Token::SAR ||
2615 op == Token::SHL ||
2616 op == Token::SHR) {
2617 if (kSmiValueSize == 32) return BinaryOpIC::SMI;
2618 return BinaryOpIC::INT32;
2619 }
2620 return BinaryOpIC::ODDBALL;
2621 }
2622 return BinaryOpIC::GENERIC;
2623}
2624
2625
2626static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type,
2627 Handle<Object> value,
2628 Token::Value op) {
2629 BinaryOpIC::TypeInfo new_type = TypeInfoFromValue(value, op);
2630 if (old_type == BinaryOpIC::STRING) {
2631 if (new_type == BinaryOpIC::STRING) return new_type;
2632 return BinaryOpIC::GENERIC;
2633 }
2634 return Max(old_type, new_type);
2635}
2636
2637
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002638#ifdef DEBUG
2639static void TraceBinaryOp(BinaryOpIC::TypeInfo left,
2640 BinaryOpIC::TypeInfo right,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002641 Maybe<int32_t> fixed_right_arg,
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002642 BinaryOpIC::TypeInfo result) {
2643 PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002644 if (fixed_right_arg.has_value) PrintF("{%d}", fixed_right_arg.value);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002645 PrintF("->%s", BinaryOpIC::GetName(result));
2646}
2647#endif
2648
2649
danno@chromium.org40cb8782011-05-25 07:58:50 +00002650RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002651 ASSERT(args.length() == 3);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002652
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002653 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002654 Handle<Object> left = args.at<Object>(0);
2655 Handle<Object> right = args.at<Object>(1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002656 int key = args.smi_at(2);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002657 Token::Value op = BinaryOpStub::decode_op_from_minor_key(key);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002658
2659 BinaryOpIC::TypeInfo previous_left, previous_right, previous_result;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002660 BinaryOpStub::decode_types_from_minor_key(
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002661 key, &previous_left, &previous_right, &previous_result);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002662
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002663 BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op);
2664 BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002665 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002666
2667 // STRING is only used for ADD operations.
2668 if ((new_left == BinaryOpIC::STRING || new_right == BinaryOpIC::STRING) &&
danno@chromium.org160a7b02011-04-18 15:51:38 +00002669 op != Token::ADD) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002670 new_left = new_right = BinaryOpIC::GENERIC;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002671 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002672
2673 BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right);
2674 BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right);
2675
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002676 Maybe<int> previous_fixed_right_arg =
2677 BinaryOpStub::decode_fixed_right_arg_from_minor_key(key);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002678
2679 int32_t value;
2680 bool new_has_fixed_right_arg =
2681 op == Token::MOD &&
2682 right->ToInt32(&value) &&
2683 BinaryOpStub::can_encode_arg_value(value) &&
2684 (previous_overall == BinaryOpIC::UNINITIALIZED ||
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002685 (previous_fixed_right_arg.has_value &&
2686 previous_fixed_right_arg.value == value));
2687 Maybe<int32_t> new_fixed_right_arg(
2688 new_has_fixed_right_arg, new_has_fixed_right_arg ? value : 1);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002689
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002690 if (previous_fixed_right_arg.has_value == new_fixed_right_arg.has_value) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002691 if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) {
2692 if (op == Token::DIV ||
2693 op == Token::MUL ||
2694 op == Token::SHR ||
2695 kSmiValueSize == 32) {
2696 // Arithmetic on two Smi inputs has yielded a heap number.
2697 // That is the only way to get here from the Smi stub.
2698 // With 32-bit Smis, all overflows give heap numbers, but with
2699 // 31-bit Smis, most operations overflow to int32 results.
2700 result_type = BinaryOpIC::NUMBER;
2701 } else {
2702 // Other operations on SMIs that overflow yield int32s.
2703 result_type = BinaryOpIC::INT32;
2704 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002705 }
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002706 if (new_overall == BinaryOpIC::INT32 &&
2707 previous_overall == BinaryOpIC::INT32) {
2708 if (new_left == previous_left && new_right == previous_right) {
2709 result_type = BinaryOpIC::NUMBER;
2710 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002711 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002712 }
2713
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002714 BinaryOpStub stub(key, new_left, new_right, result_type, new_fixed_right_arg);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002715 Handle<Code> code = stub.GetCode(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002716 if (!code.is_null()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002717#ifdef DEBUG
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002718 if (FLAG_trace_ic) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002719 PrintF("[BinaryOpIC in ");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002720 JavaScriptFrame::PrintTop(isolate, stdout, false, true);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002721 PrintF(" ");
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002722 TraceBinaryOp(previous_left, previous_right, previous_fixed_right_arg,
2723 previous_result);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002724 PrintF(" => ");
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002725 TraceBinaryOp(new_left, new_right, new_fixed_right_arg, result_type);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002726 PrintF(" #%s @ %p]\n", Token::Name(op), static_cast<void*>(*code));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002727 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002728#endif
danno@chromium.org40cb8782011-05-25 07:58:50 +00002729 BinaryOpIC ic(isolate);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002730 ic.patch(*code);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002731
2732 // Activate inlined smi code.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002733 if (previous_overall == BinaryOpIC::UNINITIALIZED) {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002734 PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002735 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002736 }
2737
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002738 Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002739 Object* builtin = NULL; // Initialization calms down the compiler.
2740 switch (op) {
2741 case Token::ADD:
2742 builtin = builtins->javascript_builtin(Builtins::ADD);
2743 break;
2744 case Token::SUB:
2745 builtin = builtins->javascript_builtin(Builtins::SUB);
2746 break;
2747 case Token::MUL:
2748 builtin = builtins->javascript_builtin(Builtins::MUL);
2749 break;
2750 case Token::DIV:
2751 builtin = builtins->javascript_builtin(Builtins::DIV);
2752 break;
2753 case Token::MOD:
2754 builtin = builtins->javascript_builtin(Builtins::MOD);
2755 break;
2756 case Token::BIT_AND:
2757 builtin = builtins->javascript_builtin(Builtins::BIT_AND);
2758 break;
2759 case Token::BIT_OR:
2760 builtin = builtins->javascript_builtin(Builtins::BIT_OR);
2761 break;
2762 case Token::BIT_XOR:
2763 builtin = builtins->javascript_builtin(Builtins::BIT_XOR);
2764 break;
2765 case Token::SHR:
2766 builtin = builtins->javascript_builtin(Builtins::SHR);
2767 break;
2768 case Token::SAR:
2769 builtin = builtins->javascript_builtin(Builtins::SAR);
2770 break;
2771 case Token::SHL:
2772 builtin = builtins->javascript_builtin(Builtins::SHL);
2773 break;
2774 default:
2775 UNREACHABLE();
2776 }
2777
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002778 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002779
2780 bool caught_exception;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002781 Handle<Object> builtin_args[] = { right };
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002782 Handle<Object> result = Execution::Call(builtin_function,
2783 left,
2784 ARRAY_SIZE(builtin_args),
2785 builtin_args,
2786 &caught_exception);
2787 if (caught_exception) {
2788 return Failure::Exception();
2789 }
2790 return *result;
2791}
2792
2793
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002794Code* CompareIC::GetRawUninitialized(Token::Value op) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002795 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002796 Code* code = NULL;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002797 CHECK(stub.FindCodeInCache(&code, Isolate::Current()));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002798 return code;
2799}
2800
2801
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002802Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002803 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002804 return stub.GetCode(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002805}
2806
2807
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002808const char* CompareIC::GetStateName(State state) {
2809 switch (state) {
2810 case UNINITIALIZED: return "UNINITIALIZED";
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002811 case SMI: return "SMI";
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002812 case NUMBER: return "NUMBER";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002813 case INTERNALIZED_STRING: return "INTERNALIZED_STRING";
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002814 case STRING: return "STRING";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002815 case UNIQUE_NAME: return "UNIQUE_NAME";
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002816 case OBJECT: return "OBJECT";
2817 case KNOWN_OBJECT: return "KNOWN_OBJECT";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002818 case GENERIC: return "GENERIC";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002819 }
danno@chromium.org41728482013-06-12 22:31:22 +00002820 UNREACHABLE();
2821 return NULL;
2822}
2823
2824
2825Handle<Type> CompareIC::StateToType(
2826 Isolate* isolate,
2827 CompareIC::State state,
2828 Handle<Map> map) {
2829 switch (state) {
2830 case CompareIC::UNINITIALIZED:
2831 return handle(Type::None(), isolate);
2832 case CompareIC::SMI:
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002833 return handle(Type::Smi(), isolate);
danno@chromium.org41728482013-06-12 22:31:22 +00002834 case CompareIC::NUMBER:
2835 return handle(Type::Number(), isolate);
2836 case CompareIC::STRING:
2837 return handle(Type::String(), isolate);
2838 case CompareIC::INTERNALIZED_STRING:
2839 return handle(Type::InternalizedString(), isolate);
2840 case CompareIC::UNIQUE_NAME:
2841 return handle(Type::UniqueName(), isolate);
2842 case CompareIC::OBJECT:
2843 return handle(Type::Receiver(), isolate);
2844 case CompareIC::KNOWN_OBJECT:
2845 return handle(
2846 map.is_null() ? Type::Receiver() : Type::Class(map), isolate);
2847 case CompareIC::GENERIC:
2848 return handle(Type::Any(), isolate);
2849 }
2850 UNREACHABLE();
2851 return Handle<Type>();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002852}
2853
2854
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002855void CompareIC::StubInfoToType(int stub_minor_key,
2856 Handle<Type>* left_type,
2857 Handle<Type>* right_type,
2858 Handle<Type>* overall_type,
2859 Handle<Map> map,
2860 Isolate* isolate) {
2861 State left_state, right_state, handler_state;
2862 ICCompareStub::DecodeMinorKey(stub_minor_key, &left_state, &right_state,
2863 &handler_state, NULL);
2864 *left_type = StateToType(isolate, left_state);
2865 *right_type = StateToType(isolate, right_state);
2866 *overall_type = StateToType(isolate, handler_state, map);
2867}
2868
2869
2870CompareIC::State CompareIC::NewInputState(State old_state,
2871 Handle<Object> value) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002872 switch (old_state) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002873 case UNINITIALIZED:
2874 if (value->IsSmi()) return SMI;
2875 if (value->IsHeapNumber()) return NUMBER;
2876 if (value->IsInternalizedString()) return INTERNALIZED_STRING;
2877 if (value->IsString()) return STRING;
2878 if (value->IsSymbol()) return UNIQUE_NAME;
2879 if (value->IsJSObject()) return OBJECT;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002880 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002881 case SMI:
2882 if (value->IsSmi()) return SMI;
2883 if (value->IsHeapNumber()) return NUMBER;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002884 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002885 case NUMBER:
2886 if (value->IsNumber()) return NUMBER;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002887 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002888 case INTERNALIZED_STRING:
2889 if (value->IsInternalizedString()) return INTERNALIZED_STRING;
2890 if (value->IsString()) return STRING;
2891 if (value->IsSymbol()) return UNIQUE_NAME;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002892 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002893 case STRING:
2894 if (value->IsString()) return STRING;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002895 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002896 case UNIQUE_NAME:
2897 if (value->IsUniqueName()) return UNIQUE_NAME;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002898 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002899 case OBJECT:
2900 if (value->IsJSObject()) return OBJECT;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002901 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002902 case GENERIC:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002903 break;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002904 case KNOWN_OBJECT:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002905 UNREACHABLE();
2906 break;
2907 }
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002908 return GENERIC;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002909}
2910
2911
2912CompareIC::State CompareIC::TargetState(State old_state,
2913 State old_left,
2914 State old_right,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002915 bool has_inlined_smi_code,
2916 Handle<Object> x,
2917 Handle<Object> y) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002918 switch (old_state) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002919 case UNINITIALIZED:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002920 if (x->IsSmi() && y->IsSmi()) return SMI;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002921 if (x->IsNumber() && y->IsNumber()) return NUMBER;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002922 if (Token::IsOrderedRelationalCompareOp(op_)) {
2923 // Ordered comparisons treat undefined as NaN, so the
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002924 // NUMBER stub will do the right thing.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002925 if ((x->IsNumber() && y->IsUndefined()) ||
2926 (y->IsNumber() && x->IsUndefined())) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002927 return NUMBER;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002928 }
2929 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002930 if (x->IsInternalizedString() && y->IsInternalizedString()) {
2931 // We compare internalized strings as plain ones if we need to determine
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002932 // the order in a non-equality compare.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002933 return Token::IsEqualityOp(op_) ? INTERNALIZED_STRING : STRING;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002934 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002935 if (x->IsString() && y->IsString()) return STRING;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002936 if (!Token::IsEqualityOp(op_)) return GENERIC;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002937 if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002938 if (x->IsJSObject() && y->IsJSObject()) {
2939 if (Handle<JSObject>::cast(x)->map() ==
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002940 Handle<JSObject>::cast(y)->map()) {
2941 return KNOWN_OBJECT;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002942 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002943 return OBJECT;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002944 }
2945 }
2946 return GENERIC;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002947 case SMI:
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002948 return x->IsNumber() && y->IsNumber() ? NUMBER : GENERIC;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002949 case INTERNALIZED_STRING:
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002950 ASSERT(Token::IsEqualityOp(op_));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002951 if (x->IsString() && y->IsString()) return STRING;
2952 if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
2953 return GENERIC;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002954 case NUMBER:
2955 // If the failure was due to one side changing from smi to heap number,
2956 // then keep the state (if other changed at the same time, we will get
2957 // a second miss and then go to generic).
2958 if (old_left == SMI && x->IsHeapNumber()) return NUMBER;
2959 if (old_right == SMI && y->IsHeapNumber()) return NUMBER;
2960 return GENERIC;
2961 case KNOWN_OBJECT:
2962 ASSERT(Token::IsEqualityOp(op_));
2963 if (x->IsJSObject() && y->IsJSObject()) return OBJECT;
2964 return GENERIC;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002965 case STRING:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002966 case UNIQUE_NAME:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002967 case OBJECT:
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002968 case GENERIC:
2969 return GENERIC;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002970 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002971 UNREACHABLE();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002972 return GENERIC; // Make the compiler happy.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002973}
2974
2975
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002976void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002977 HandleScope scope(isolate());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002978 State previous_left, previous_right, previous_state;
2979 ICCompareStub::DecodeMinorKey(target()->stub_info(), &previous_left,
2980 &previous_right, &previous_state, NULL);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002981 State new_left = NewInputState(previous_left, x);
2982 State new_right = NewInputState(previous_right, y);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002983 State state = TargetState(previous_state, previous_left, previous_right,
2984 HasInlinedSmiCode(address()), x, y);
2985 ICCompareStub stub(op_, new_left, new_right, state);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002986 if (state == KNOWN_OBJECT) {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00002987 stub.set_known_map(
2988 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate()));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002989 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002990 set_target(*stub.GetCode(isolate()));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002991
2992#ifdef DEBUG
2993 if (FLAG_trace_ic) {
2994 PrintF("[CompareIC in ");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002995 JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002996 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n",
2997 GetStateName(previous_left),
2998 GetStateName(previous_right),
2999 GetStateName(previous_state),
3000 GetStateName(new_left),
3001 GetStateName(new_right),
3002 GetStateName(state),
3003 Token::Name(op_),
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003004 static_cast<void*>(*stub.GetCode(isolate())));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003005 }
3006#endif
3007
3008 // Activate inlined smi code.
3009 if (previous_state == UNINITIALIZED) {
3010 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
3011 }
3012}
3013
3014
3015// Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003016RUNTIME_FUNCTION(Code*, CompareIC_Miss) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003017 SealHandleScope shs(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003018 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003019 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003020 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
3021 return ic.target();
3022}
3023
3024
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003025void CompareNilIC::Clear(Address address, Code* target) {
3026 if (target->ic_state() == UNINITIALIZED) return;
3027 Code::ExtraICState state = target->extended_extra_ic_state();
3028
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003029 CompareNilICStub stub(state, HydrogenCodeStub::UNINITIALIZED);
danno@chromium.org41728482013-06-12 22:31:22 +00003030 stub.ClearState();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003031
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003032 Code* code = NULL;
3033 CHECK(stub.FindCodeInCache(&code, target->GetIsolate()));
3034
3035 SetTargetAtAddress(address, code);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003036}
3037
3038
ulan@chromium.org837a67e2013-06-11 15:39:48 +00003039MaybeObject* CompareNilIC::DoCompareNilSlow(NilValue nil,
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003040 Handle<Object> object) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003041 if (object->IsNull() || object->IsUndefined()) {
3042 return Smi::FromInt(true);
3043 }
3044 return Smi::FromInt(object->IsUndetectableObject());
3045}
3046
3047
3048MaybeObject* CompareNilIC::CompareNil(Handle<Object> object) {
3049 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
3050
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003051 CompareNilICStub stub(extra_ic_state);
3052
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003053 // Extract the current supported types from the patched IC and calculate what
3054 // types must be supported as a result of the miss.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003055 bool already_monomorphic = stub.IsMonomorphic();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003056
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00003057 stub.UpdateStatus(object);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003058
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003059 NilValue nil = stub.GetNilValue();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003060
3061 // Find or create the specialized stub to support the new set of types.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003062 Handle<Code> code;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003063 if (stub.IsMonomorphic()) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003064 Handle<Map> monomorphic_map(already_monomorphic
3065 ? target()->FindFirstMap()
3066 : HeapObject::cast(*object)->map());
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003067 code = isolate()->stub_cache()->ComputeCompareNil(monomorphic_map, stub);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003068 } else {
3069 code = stub.GetCode(isolate());
3070 }
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00003071 set_target(*code);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00003072 return DoCompareNilSlow(nil, object);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003073}
3074
3075
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003076RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss) {
3077 HandleScope scope(isolate);
3078 Handle<Object> object = args.at<Object>(0);
3079 CompareNilIC ic(isolate);
3080 return ic.CompareNil(object);
3081}
3082
3083
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003084RUNTIME_FUNCTION(MaybeObject*, Unreachable) {
3085 UNREACHABLE();
3086 CHECK(false);
3087 return isolate->heap()->undefined_value();
3088}
3089
3090
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00003091MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object,
3092 Code::ExtraICState extra_ic_state) {
3093 ToBooleanStub stub(extra_ic_state);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00003094 bool to_boolean_value = stub.UpdateStatus(object);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00003095 Handle<Code> code = stub.GetCode(isolate());
3096 set_target(*code);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00003097 return Smi::FromInt(to_boolean_value ? 1 : 0);
3098}
3099
3100
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00003101RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss) {
3102 ASSERT(args.length() == 1);
3103 HandleScope scope(isolate);
3104 Handle<Object> object = args.at<Object>(0);
3105 ToBooleanIC ic(isolate);
3106 Code::ExtraICState ic_state = ic.target()->extended_extra_ic_state();
3107 return ic.ToBoolean(object, ic_state);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00003108}
3109
3110
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003111static const Address IC_utilities[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003112#define ADDR(name) FUNCTION_ADDR(name),
3113 IC_UTIL_LIST(ADDR)
3114 NULL
3115#undef ADDR
3116};
3117
3118
3119Address IC::AddressFromUtilityId(IC::UtilityId id) {
3120 return IC_utilities[id];
3121}
3122
3123
3124} } // namespace v8::internal