blob: 0d0b93570bca0087efb7cdd589c3112575170878 [file] [log] [blame]
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001// Copyright 2011 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
kasperl@chromium.orgba86cd62009-05-27 08:46:40 +000043static char TransitionMarkFromState(IC::State state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044 switch (state) {
45 case UNINITIALIZED: return '0';
ager@chromium.org5ec48922009-05-05 07:25:34 +000046 case PREMONOMORPHIC: return 'P';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047 case MONOMORPHIC: return '1';
48 case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
49 case MEGAMORPHIC: return 'N';
50
51 // We never see the debugger states here, because the state is
52 // computed from the original code - not the patched code. Let
53 // these cases fall through to the unreachable code below.
54 case DEBUG_BREAK: break;
55 case DEBUG_PREPARE_STEP_IN: break;
56 }
57 UNREACHABLE();
58 return 0;
59}
60
61void IC::TraceIC(const char* type,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000062 Handle<Object> name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063 State old_state,
kasperl@chromium.org71affb52009-05-26 05:44:31 +000064 Code* new_target,
65 const char* extra_info) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066 if (FLAG_trace_ic) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000067 State new_state = StateFrom(new_target,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000068 HEAP->undefined_value(),
69 HEAP->undefined_value());
ager@chromium.orgea91cc52011-05-23 06:06:11 +000070 PrintF("[%s in ", type);
71 StackFrameIterator it;
72 while (it.frame()->fp() != this->fp()) it.Advance();
73 StackFrame* raw_frame = it.frame();
74 if (raw_frame->is_internal()) {
75 Isolate* isolate = new_target->GetIsolate();
76 Code* apply_builtin = isolate->builtins()->builtin(
77 Builtins::kFunctionApply);
78 if (raw_frame->unchecked_code() == apply_builtin) {
79 PrintF("apply from ");
80 it.Advance();
81 raw_frame = it.frame();
82 }
83 }
84 if (raw_frame->is_java_script()) {
85 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
86 Code* js_code = frame->unchecked_code();
87 // Find the function on the stack and both the active code for the
88 // function and the original code.
89 JSFunction* function = JSFunction::cast(frame->function());
90 function->PrintName();
vegorov@chromium.org7943d462011-08-01 11:41:52 +000091 int code_offset =
92 static_cast<int>(address() - js_code->instruction_start());
ager@chromium.orgea91cc52011-05-23 06:06:11 +000093 PrintF("+%d", code_offset);
94 } else {
95 PrintF("<unknown>");
96 }
97 PrintF(" (%c->%c)%s",
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098 TransitionMarkFromState(old_state),
kasperl@chromium.org71affb52009-05-26 05:44:31 +000099 TransitionMarkFromState(new_state),
100 extra_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101 name->Print();
102 PrintF("]\n");
103 }
104}
105#endif
106
107
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000108IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) {
109 ASSERT(isolate == Isolate::Current());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110 // To improve the performance of the (much used) IC code, we unfold
111 // a few levels of the stack frame iteration code. This yields a
112 // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 const Address entry =
114 Isolate::c_entry_fp(isolate->thread_local_top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000115 Address* pc_address =
116 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
117 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
118 // If there's another JavaScript frame on the stack, we need to look
119 // one frame further down the stack to find the frame pointer and
120 // the return address stack slot.
121 if (depth == EXTRA_CALL_FRAME) {
122 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
123 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
124 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
125 }
126#ifdef DEBUG
127 StackFrameIterator it;
128 for (int i = 0; i < depth + 1; i++) it.Advance();
129 StackFrame* frame = it.frame();
130 ASSERT(fp == frame->fp() && pc_address == frame->pc_address());
131#endif
132 fp_ = fp;
133 pc_address_ = pc_address;
134}
135
136
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000137#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000138Address IC::OriginalCodeAddress() {
139 HandleScope scope;
140 // Compute the JavaScript frame for the frame pointer of this IC
141 // structure. We need this to be able to find the function
142 // corresponding to the frame.
143 StackFrameIterator it;
144 while (it.frame()->fp() != this->fp()) it.Advance();
145 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
146 // Find the function on the stack and both the active code for the
147 // function and the original code.
148 JSFunction* function = JSFunction::cast(frame->function());
149 Handle<SharedFunctionInfo> shared(function->shared());
150 Code* code = shared->code();
151 ASSERT(Debug::HasDebugInfo(shared));
152 Code* original_code = Debug::GetDebugInfo(shared)->original_code();
153 ASSERT(original_code->IsCode());
154 // Get the address of the call site in the active code. This is the
155 // place where the call to DebugBreakXXX is and where the IC
156 // normally would be.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000157 Address addr = pc() - Assembler::kCallTargetAddressOffset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158 // Return the address in the original code. This is the place where
ager@chromium.org32912102009-01-16 10:38:43 +0000159 // the call which has been overwritten by the DebugBreakXXX resides
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000160 // and the place where the inline cache system should look.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000161 intptr_t delta =
162 original_code->instruction_start() - code->instruction_start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000163 return addr + delta;
164}
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000165#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000166
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000167
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168static bool HasNormalObjectsInPrototypeChain(Isolate* isolate,
169 LookupResult* lookup,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000170 Object* receiver) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000171 Object* end = lookup->IsProperty()
172 ? lookup->holder() : isolate->heap()->null_value();
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000173 for (Object* current = receiver;
174 current != end;
175 current = current->GetPrototype()) {
176 if (current->IsJSObject() &&
177 !JSObject::cast(current)->HasFastProperties() &&
178 !current->IsJSGlobalProxy() &&
179 !current->IsJSGlobalObject()) {
180 return true;
181 }
182 }
183
184 return false;
185}
186
187
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000188static bool TryRemoveInvalidPrototypeDependentStub(Code* target,
189 Object* receiver,
190 Object* name) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000191 InlineCacheHolderFlag cache_holder =
192 Code::ExtractCacheHolderFromFlags(target->flags());
193
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000194 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) {
195 // The stub was generated for JSObject but called for non-JSObject.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000196 // IC::GetCodeCacheHolder is not applicable.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000197 return false;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000198 } else if (cache_holder == PROTOTYPE_MAP &&
199 receiver->GetPrototype()->IsNull()) {
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;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000202 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000203 Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204
205 // Decide whether the inline cache failed because of changes to the
206 // receiver itself or changes to one of its prototypes.
207 //
208 // If there are changes to the receiver itself, the map of the
209 // receiver will have changed and the current target will not be in
210 // the receiver map's code cache. Therefore, if the current target
211 // is in the receiver map's code cache, the inline cache failed due
212 // to prototype check failure.
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +0000213 int index = map->IndexInCodeCache(name, target);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000214 if (index >= 0) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000215 map->RemoveFromCodeCache(String::cast(name), target, index);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000216 return true;
217 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000218
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000219 return false;
220}
221
222
223IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
224 IC::State state = target->ic_state();
225
226 if (state != MONOMORPHIC || !name->IsString()) return state;
227 if (receiver->IsUndefined() || receiver->IsNull()) return state;
228
229 // For keyed load/store/call, the most likely cause of cache failure is
230 // that the key has changed. We do not distinguish between
231 // prototype and non-prototype failures for keyed access.
232 Code::Kind kind = target->kind();
233 if (kind == Code::KEYED_LOAD_IC ||
234 kind == Code::KEYED_STORE_IC ||
235 kind == Code::KEYED_CALL_IC) {
236 return MONOMORPHIC;
237 }
238
239 // Remove the target from the code cache if it became invalid
240 // because of changes in the prototype chain to avoid hitting it
241 // again.
242 // Call stubs handle this later to allow extra IC state
243 // transitions.
244 if (kind != Code::CALL_IC &&
245 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000246 return MONOMORPHIC_PROTOTYPE_FAILURE;
247 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000248
249 // The builtins object is special. It only changes when JavaScript
250 // builtins are loaded lazily. It is important to keep inline
251 // caches for the builtins object monomorphic. Therefore, if we get
252 // an inline cache miss for the builtins object after lazily loading
ager@chromium.org236ad962008-09-25 09:45:57 +0000253 // JavaScript builtins, we return uninitialized as the state to
254 // force the inline cache back to monomorphic state.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000255 if (receiver->IsJSBuiltinsObject()) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000256 return UNINITIALIZED;
257 }
258
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000259 return MONOMORPHIC;
260}
261
262
ager@chromium.org236ad962008-09-25 09:45:57 +0000263RelocInfo::Mode IC::ComputeMode() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000264 Address addr = address();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000265 Code* code = Code::cast(isolate()->heap()->FindCodeObject(addr));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000266 for (RelocIterator it(code, RelocInfo::kCodeTargetMask);
267 !it.done(); it.next()) {
268 RelocInfo* info = it.rinfo();
269 if (info->pc() == addr) return info->rmode();
270 }
271 UNREACHABLE();
ager@chromium.org236ad962008-09-25 09:45:57 +0000272 return RelocInfo::NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000273}
274
275
276Failure* IC::TypeError(const char* type,
277 Handle<Object> object,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000278 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000279 HandleScope scope(isolate());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000280 Handle<Object> args[2] = { key, object };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000281 Handle<Object> error = isolate()->factory()->NewTypeError(
282 type, HandleVector(args, 2));
283 return isolate()->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000284}
285
286
287Failure* IC::ReferenceError(const char* type, Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000288 HandleScope scope(isolate());
289 Handle<Object> error = isolate()->factory()->NewReferenceError(
290 type, HandleVector(&name, 1));
291 return isolate()->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000292}
293
294
295void IC::Clear(Address address) {
296 Code* target = GetTargetAtAddress(address);
297
298 // Don't clear debug break inline cache as it will remove the break point.
kasper.lund7276f142008-07-30 08:49:36 +0000299 if (target->ic_state() == DEBUG_BREAK) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000300
301 switch (target->kind()) {
302 case Code::LOAD_IC: return LoadIC::Clear(address, target);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000303 case Code::KEYED_LOAD_IC:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000304 return KeyedLoadIC::Clear(address, target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000305 case Code::STORE_IC: return StoreIC::Clear(address, target);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000306 case Code::KEYED_STORE_IC:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000307 return KeyedStoreIC::Clear(address, target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000308 case Code::CALL_IC: return CallIC::Clear(address, target);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000309 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000310 case Code::UNARY_OP_IC:
311 case Code::BINARY_OP_IC:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000312 case Code::COMPARE_IC:
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000313 case Code::TO_BOOLEAN_IC:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000314 // Clearing these is tricky and does not
315 // make any performance difference.
316 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 default: UNREACHABLE();
318 }
319}
320
321
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000322void CallICBase::Clear(Address address, Code* target) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000323 bool contextual = CallICBase::Contextual::decode(target->extra_ic_state());
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000324 State state = target->ic_state();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000325 if (state == UNINITIALIZED) return;
326 Code* code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000327 Isolate::Current()->stub_cache()->FindCallInitialize(
328 target->arguments_count(),
329 target->ic_in_loop(),
danno@chromium.org40cb8782011-05-25 07:58:50 +0000330 contextual ? RelocInfo::CODE_TARGET_CONTEXT : RelocInfo::CODE_TARGET,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 target->kind());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000332 SetTargetAtAddress(address, code);
333}
334
335
336void KeyedLoadIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000337 if (target->ic_state() == UNINITIALIZED) return;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000338 // Make sure to also clear the map used in inline fast cases. If we
339 // do not clear these maps, cached code can keep objects alive
340 // through the embedded maps.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000341 SetTargetAtAddress(address, initialize_stub());
342}
343
344
345void LoadIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000346 if (target->ic_state() == UNINITIALIZED) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000347 SetTargetAtAddress(address, initialize_stub());
348}
349
350
351void StoreIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000352 if (target->ic_state() == UNINITIALIZED) return;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000353 SetTargetAtAddress(address,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000354 (target->extra_ic_state() == kStrictMode)
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000355 ? initialize_stub_strict()
356 : initialize_stub());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000357}
358
359
360void KeyedStoreIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000361 if (target->ic_state() == UNINITIALIZED) return;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000362 SetTargetAtAddress(address,
363 (target->extra_ic_state() == kStrictMode)
364 ? initialize_stub_strict()
365 : initialize_stub());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000366}
367
368
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000369static bool HasInterceptorGetter(JSObject* object) {
370 return !object->GetNamedInterceptor()->getter()->IsUndefined();
371}
372
373
374static void LookupForRead(Object* object,
375 String* name,
376 LookupResult* lookup) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000377 AssertNoAllocation no_gc; // pointers must stay valid
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000378
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000379 // Skip all the objects with named interceptors, but
380 // without actual getter.
381 while (true) {
382 object->Lookup(name, lookup);
383 // Besides normal conditions (property not found or it's not
ager@chromium.org5c838252010-02-19 08:53:10 +0000384 // an interceptor), bail out if lookup is not cacheable: we won't
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000385 // be able to IC it anyway and regular lookup should work fine.
ager@chromium.org5c838252010-02-19 08:53:10 +0000386 if (!lookup->IsFound()
387 || (lookup->type() != INTERCEPTOR)
388 || !lookup->IsCacheable()) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000389 return;
390 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000391
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000392 JSObject* holder = lookup->holder();
393 if (HasInterceptorGetter(holder)) {
394 return;
395 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000396
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000397 holder->LocalLookupRealNamedProperty(name, lookup);
ager@chromium.org5c838252010-02-19 08:53:10 +0000398 if (lookup->IsProperty()) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000399 ASSERT(lookup->type() != INTERCEPTOR);
400 return;
401 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000402
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000403 Object* proto = holder->GetPrototype();
404 if (proto->IsNull()) {
405 lookup->NotFound();
406 return;
407 }
408
409 object = proto;
410 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000411}
412
413
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000414Object* CallICBase::TryCallAsFunction(Object* object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 HandleScope scope(isolate());
416 Handle<Object> target(object, isolate());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000417 Handle<Object> delegate = Execution::GetFunctionDelegate(target);
418
419 if (delegate->IsJSFunction()) {
420 // Patch the receiver and use the delegate as the function to
421 // invoke. This is used for invoking objects as if they were
422 // functions.
423 const int argc = this->target()->arguments_count();
424 StackFrameLocator locator;
425 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
426 int index = frame->ComputeExpressionsCount() - (argc + 1);
427 frame->SetExpression(index, *target);
428 }
429
430 return *delegate;
431}
432
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000433
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000434void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee,
435 Handle<Object> object) {
436 if (callee->IsJSFunction()) {
437 Handle<JSFunction> function = Handle<JSFunction>::cast(callee);
438 if (function->shared()->strict_mode() || function->IsBuiltin()) {
439 // Do not wrap receiver for strict mode functions or for builtins.
440 return;
441 }
442 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000443
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000444 // And only wrap string, number or boolean.
445 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
446 // Change the receiver to the result of calling ToObject on it.
447 const int argc = this->target()->arguments_count();
448 StackFrameLocator locator;
449 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
450 int index = frame->ComputeExpressionsCount() - (argc + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000451 frame->SetExpression(index, *isolate()->factory()->ToObject(object));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000452 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000453}
454
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000455
lrn@chromium.org303ada72010-10-27 09:33:13 +0000456MaybeObject* CallICBase::LoadFunction(State state,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000457 Code::ExtraICState extra_ic_state,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000458 Handle<Object> object,
459 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000460 // If the object is undefined or null it's illegal to try to get any
461 // of its properties; throw a TypeError in that case.
462 if (object->IsUndefined() || object->IsNull()) {
463 return TypeError("non_object_property_call", object, name);
464 }
465
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000466 // Check if the name is trivially convertible to an index and get
467 // the element if so.
468 uint32_t index;
469 if (name->AsArrayIndex(&index)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000470 Object* result;
471 { MaybeObject* maybe_result = object->GetElement(index);
472 if (!maybe_result->ToObject(&result)) return maybe_result;
473 }
474
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000475 if (result->IsJSFunction()) return result;
476
477 // Try to find a suitable function delegate for the object at hand.
478 result = TryCallAsFunction(result);
479 if (result->IsJSFunction()) return result;
480
481 // Otherwise, it will fail in the lookup step.
482 }
483
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000484 // Lookup the property in the object.
485 LookupResult lookup;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000486 LookupForRead(*object, *name, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487
ager@chromium.org5c838252010-02-19 08:53:10 +0000488 if (!lookup.IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489 // If the object does not have the requested property, check which
490 // exception we need to throw.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000491 if (IsContextual(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492 return ReferenceError("not_defined", name);
493 }
494 return TypeError("undefined_method", object, name);
495 }
496
497 // Lookup is valid: Update inline cache and stub cache.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000498 if (FLAG_use_ic) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000499 UpdateCaches(&lookup, state, extra_ic_state, object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000500 }
501
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000502 // Get the property.
503 PropertyAttributes attr;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000504 Object* result;
505 { MaybeObject* maybe_result =
506 object->GetProperty(*object, &lookup, *name, &attr);
507 if (!maybe_result->ToObject(&result)) return maybe_result;
508 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000509
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000510 if (lookup.type() == INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000511 // If the object does not have the requested property, check which
512 // exception we need to throw.
513 if (attr == ABSENT) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 if (IsContextual(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515 return ReferenceError("not_defined", name);
516 }
517 return TypeError("undefined_method", object, name);
518 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000519 }
520
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000521 ASSERT(!result->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 HandleScope scope(isolate());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000524 // Wrap result in a handle because ReceiverToObjectIfRequired may allocate
525 // new object and cause GC.
526 Handle<Object> result_handle(result);
527 // Make receiver an object if the callee requires it. Strict mode or builtin
528 // functions do not wrap the receiver, non-strict functions and objects
529 // called as functions do.
530 ReceiverToObjectIfRequired(result_handle, object);
531
532 if (result_handle->IsJSFunction()) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000533#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000534 // Handle stepping into a function if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000535 Debug* debug = isolate()->debug();
536 if (debug->StepInActive()) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000537 // Protect the result in a handle as the debugger can allocate and might
538 // cause GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 Handle<JSFunction> function(JSFunction::cast(*result_handle), isolate());
540 debug->HandleStepIn(function, object, fp(), false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000541 return *function;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000543#endif
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000544
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000545 return *result_handle;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000546 }
547
548 // Try to find a suitable function delegate for the object at hand.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000549 result_handle = Handle<Object>(TryCallAsFunction(*result_handle));
550 if (result_handle->IsJSFunction()) return *result_handle;
551
552 return TypeError("property_not_function", object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553}
554
555
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000556bool CallICBase::TryUpdateExtraICState(LookupResult* lookup,
557 Handle<Object> object,
558 Code::ExtraICState* extra_ic_state) {
559 ASSERT(kind_ == Code::CALL_IC);
560 if (lookup->type() != CONSTANT_FUNCTION) return false;
561 JSFunction* function = lookup->GetConstantFunction();
562 if (!function->shared()->HasBuiltinFunctionId()) return false;
563
564 // Fetch the arguments passed to the called function.
565 const int argc = target()->arguments_count();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000566 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000567 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
568 Arguments args(argc + 1,
569 &Memory::Object_at(fp +
570 StandardFrameConstants::kCallerSPOffset +
571 argc * kPointerSize));
572 switch (function->shared()->builtin_function_id()) {
573 case kStringCharCodeAt:
574 case kStringCharAt:
575 if (object->IsString()) {
576 String* string = String::cast(*object);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000577 // Check there's the right string value or wrapper in the receiver slot.
578 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000579 // If we're in the default (fastest) state and the index is
580 // out of bounds, update the state to record this fact.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000581 if (StringStubState::decode(*extra_ic_state) == DEFAULT_STRING_STUB &&
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000582 argc >= 1 && args[1]->IsNumber()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000583 double index = DoubleToInteger(args.number_at(1));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000584 if (index < 0 || index >= string->length()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000585 *extra_ic_state =
586 StringStubState::update(*extra_ic_state,
587 STRING_INDEX_OUT_OF_BOUNDS);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000588 return true;
589 }
590 }
591 }
592 break;
593 default:
594 return false;
595 }
596 return false;
597}
598
599
600MaybeObject* CallICBase::ComputeMonomorphicStub(
601 LookupResult* lookup,
602 State state,
603 Code::ExtraICState extra_ic_state,
604 Handle<Object> object,
605 Handle<String> name) {
606 int argc = target()->arguments_count();
607 InLoopFlag in_loop = target()->ic_in_loop();
608 MaybeObject* maybe_code = NULL;
609 switch (lookup->type()) {
610 case FIELD: {
611 int index = lookup->GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000612 maybe_code = isolate()->stub_cache()->ComputeCallField(argc,
613 in_loop,
614 kind_,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000615 extra_ic_state,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000616 *name,
617 *object,
618 lookup->holder(),
619 index);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000620 break;
621 }
622 case CONSTANT_FUNCTION: {
623 // Get the constant function and compute the code stub for this
624 // call; used for rewriting to monomorphic state and making sure
625 // that the code stub is in the stub cache.
626 JSFunction* function = lookup->GetConstantFunction();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 maybe_code =
628 isolate()->stub_cache()->ComputeCallConstant(argc,
629 in_loop,
630 kind_,
631 extra_ic_state,
632 *name,
633 *object,
634 lookup->holder(),
635 function);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000636 break;
637 }
638 case NORMAL: {
639 if (!object->IsJSObject()) return NULL;
640 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
641
642 if (lookup->holder()->IsGlobalObject()) {
643 GlobalObject* global = GlobalObject::cast(lookup->holder());
644 JSGlobalPropertyCell* cell =
645 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
646 if (!cell->value()->IsJSFunction()) return NULL;
647 JSFunction* function = JSFunction::cast(cell->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000648 maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc,
649 in_loop,
650 kind_,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000651 extra_ic_state,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000652 *name,
653 *receiver,
654 global,
655 cell,
656 function);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000657 } else {
658 // There is only one shared stub for calling normalized
659 // properties. It does not traverse the prototype chain, so the
660 // property must be found in the receiver for the stub to be
661 // applicable.
662 if (lookup->holder() != *receiver) return NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000663 maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc,
664 in_loop,
665 kind_,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000666 extra_ic_state,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000667 *name,
668 *receiver);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000669 }
670 break;
671 }
672 case INTERCEPTOR: {
673 ASSERT(HasInterceptorGetter(lookup->holder()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000674 maybe_code = isolate()->stub_cache()->ComputeCallInterceptor(
675 argc,
676 kind_,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000677 extra_ic_state,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000678 *name,
679 *object,
680 lookup->holder());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000681 break;
682 }
683 default:
684 maybe_code = NULL;
685 break;
686 }
687 return maybe_code;
688}
689
690
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000691void CallICBase::UpdateCaches(LookupResult* lookup,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000692 State state,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000693 Code::ExtraICState extra_ic_state,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000694 Handle<Object> object,
695 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 // Bail out if we didn't find a result.
ager@chromium.org5c838252010-02-19 08:53:10 +0000697 if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000699 if (lookup->holder() != *object &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000700 HasNormalObjectsInPrototypeChain(
701 isolate(), lookup, object->GetPrototype())) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000702 // Suppress optimization for prototype chains with slow properties objects
703 // in the middle.
704 return;
705 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000706
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707 // Compute the number of arguments.
708 int argc = target()->arguments_count();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000709 InLoopFlag in_loop = target()->ic_in_loop();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000710 MaybeObject* maybe_code = NULL;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000711 bool had_proto_failure = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000712 if (state == UNINITIALIZED) {
713 // This is the first time we execute this inline cache.
714 // Set the target to the pre monomorphic stub to delay
715 // setting the monomorphic state.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000716 maybe_code =
717 isolate()->stub_cache()->ComputeCallPreMonomorphic(argc,
718 in_loop,
719 kind_,
720 extra_ic_state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721 } else if (state == MONOMORPHIC) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000722 if (kind_ == Code::CALL_IC &&
723 TryUpdateExtraICState(lookup, object, &extra_ic_state)) {
724 maybe_code = ComputeMonomorphicStub(lookup,
725 state,
726 extra_ic_state,
727 object,
728 name);
729 } else if (kind_ == Code::CALL_IC &&
730 TryRemoveInvalidPrototypeDependentStub(target(),
731 *object,
732 *name)) {
733 had_proto_failure = true;
734 maybe_code = ComputeMonomorphicStub(lookup,
735 state,
736 extra_ic_state,
737 object,
738 name);
739 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000740 maybe_code =
741 isolate()->stub_cache()->ComputeCallMegamorphic(argc,
742 in_loop,
743 kind_,
744 extra_ic_state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000745 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000746 } else {
747 maybe_code = ComputeMonomorphicStub(lookup,
748 state,
749 extra_ic_state,
750 object,
751 name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000752 }
753
754 // If we're unable to compute the stub (not enough memory left), we
755 // simply avoid updating the caches.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000756 Object* code;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000757 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000758
759 // Patch the call site depending on the state of the cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000760 if (state == UNINITIALIZED ||
761 state == PREMONOMORPHIC ||
762 state == MONOMORPHIC ||
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000763 state == MONOMORPHIC_PROTOTYPE_FAILURE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764 set_target(Code::cast(code));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000765 } else if (state == MEGAMORPHIC) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000766 // Cache code holding map should be consistent with
767 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub.
768 Map* map = JSObject::cast(object->IsJSObject() ? *object :
769 object->GetPrototype())->map();
770
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000771 // Update the stub cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000772 isolate()->stub_cache()->Set(*name, map, Code::cast(code));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773 }
774
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000775 USE(had_proto_failure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000776#ifdef DEBUG
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000777 if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000778 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
779 name, state, target(), in_loop ? " (in-loop)" : "");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000780#endif
781}
782
783
lrn@chromium.org303ada72010-10-27 09:33:13 +0000784MaybeObject* KeyedCallIC::LoadFunction(State state,
785 Handle<Object> object,
786 Handle<Object> key) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000787 if (key->IsSymbol()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000788 return CallICBase::LoadFunction(state,
789 Code::kNoExtraICState,
790 object,
791 Handle<String>::cast(key));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000792 }
793
794 if (object->IsUndefined() || object->IsNull()) {
795 return TypeError("non_object_property_call", object, key);
796 }
797
whesse@chromium.org7b260152011-06-20 15:33:18 +0000798 if (FLAG_use_ic && state != MEGAMORPHIC && object->IsHeapObject()) {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000799 int argc = target()->arguments_count();
800 InLoopFlag in_loop = target()->ic_in_loop();
whesse@chromium.org7b260152011-06-20 15:33:18 +0000801 Heap* heap = Handle<HeapObject>::cast(object)->GetHeap();
802 Map* map = heap->non_strict_arguments_elements_map();
803 if (object->IsJSObject() &&
804 Handle<JSObject>::cast(object)->elements()->map() == map) {
805 MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallArguments(
806 argc, in_loop, Code::KEYED_CALL_IC);
807 Object* code;
808 if (maybe_code->ToObject(&code)) {
809 set_target(Code::cast(code));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000810#ifdef DEBUG
whesse@chromium.org7b260152011-06-20 15:33:18 +0000811 TraceIC(
812 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : "");
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000813#endif
whesse@chromium.org7b260152011-06-20 15:33:18 +0000814 }
815 } else if (FLAG_use_ic && state != MEGAMORPHIC &&
816 !object->IsAccessCheckNeeded()) {
817 MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(
818 argc, in_loop, Code::KEYED_CALL_IC, Code::kNoExtraICState);
819 Object* code;
820 if (maybe_code->ToObject(&code)) {
821 set_target(Code::cast(code));
822#ifdef DEBUG
823 TraceIC(
824 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : "");
825#endif
826 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000827 }
828 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000829
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000830 HandleScope scope(isolate());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000831 Handle<Object> result = GetProperty(object, key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000832 RETURN_IF_EMPTY_HANDLE(isolate(), result);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000833
834 // Make receiver an object if the callee requires it. Strict mode or builtin
835 // functions do not wrap the receiver, non-strict functions and objects
836 // called as functions do.
837 ReceiverToObjectIfRequired(result, object);
838
839 if (result->IsJSFunction()) return *result;
840 result = Handle<Object>(TryCallAsFunction(*result));
841 if (result->IsJSFunction()) return *result;
842
843 return TypeError("property_not_function", object, key);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000844}
845
846
lrn@chromium.org303ada72010-10-27 09:33:13 +0000847MaybeObject* LoadIC::Load(State state,
848 Handle<Object> object,
849 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000850 // If the object is undefined or null it's illegal to try to get any
851 // of its properties; throw a TypeError in that case.
852 if (object->IsUndefined() || object->IsNull()) {
853 return TypeError("non_object_property_load", object, name);
854 }
855
856 if (FLAG_use_ic) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000857 // Use specialized code for getting the length of strings and
858 // string wrapper objects. The length property of string wrapper
859 // objects is read-only and therefore always returns the length of
860 // the underlying string value. See ECMA-262 15.5.5.1.
861 if ((object->IsString() || object->IsStringWrapper()) &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000862 name->Equals(isolate()->heap()->length_symbol())) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000863 AssertNoAllocation no_allocation;
864 Code* stub = NULL;
865 if (state == UNINITIALIZED) {
866 stub = pre_monomorphic_stub();
867 } else if (state == PREMONOMORPHIC) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000868 if (object->IsString()) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000869 stub = isolate()->builtins()->builtin(
870 Builtins::kLoadIC_StringLength);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000871 } else {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000872 stub = isolate()->builtins()->builtin(
873 Builtins::kLoadIC_StringWrapperLength);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000874 }
875 } else if (state == MONOMORPHIC && object->IsStringWrapper()) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000876 stub = isolate()->builtins()->builtin(
877 Builtins::kLoadIC_StringWrapperLength);
878 } else if (state != MEGAMORPHIC) {
879 stub = megamorphic_stub();
880 }
881 if (stub != NULL) {
882 set_target(stub);
883#ifdef DEBUG
884 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
885#endif
ager@chromium.org378b34e2011-01-28 08:04:38 +0000886 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000887 // Get the string if we have a string wrapper object.
888 if (object->IsJSValue()) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000889 return Smi::FromInt(
890 String::cast(Handle<JSValue>::cast(object)->value())->length());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000891 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000892 return Smi::FromInt(String::cast(*object)->length());
893 }
894
895 // Use specialized code for getting the length of arrays.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000896 if (object->IsJSArray() &&
897 name->Equals(isolate()->heap()->length_symbol())) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000898 AssertNoAllocation no_allocation;
899 Code* stub = NULL;
900 if (state == UNINITIALIZED) {
901 stub = pre_monomorphic_stub();
902 } else if (state == PREMONOMORPHIC) {
903 stub = isolate()->builtins()->builtin(
904 Builtins::kLoadIC_ArrayLength);
905 } else if (state != MEGAMORPHIC) {
906 stub = megamorphic_stub();
907 }
908 if (stub != NULL) {
909 set_target(stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000910#ifdef DEBUG
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000911 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000912#endif
ager@chromium.org378b34e2011-01-28 08:04:38 +0000913 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914 return JSArray::cast(*object)->length();
915 }
916
917 // Use specialized code for getting prototype of functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 if (object->IsJSFunction() &&
919 name->Equals(isolate()->heap()->prototype_symbol()) &&
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000920 JSFunction::cast(*object)->should_have_prototype()) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000921 { AssertNoAllocation no_allocation;
922 Code* stub = NULL;
923 if (state == UNINITIALIZED) {
924 stub = pre_monomorphic_stub();
925 } else if (state == PREMONOMORPHIC) {
926 stub = isolate()->builtins()->builtin(
927 Builtins::kLoadIC_FunctionPrototype);
928 } else if (state != MEGAMORPHIC) {
929 stub = megamorphic_stub();
930 }
931 if (stub != NULL) {
932 set_target(stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933#ifdef DEBUG
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000934 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000935#endif
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000936 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000937 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938 return Accessors::FunctionGetPrototype(*object, 0);
939 }
940 }
941
942 // Check if the name is trivially convertible to an index and get
943 // the element if so.
944 uint32_t index;
945 if (name->AsArrayIndex(&index)) return object->GetElement(index);
946
947 // Named lookup in the object.
948 LookupResult lookup;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000949 LookupForRead(*object, *name, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000950
ager@chromium.org5c838252010-02-19 08:53:10 +0000951 // If we did not find a property, check if we need to throw an exception.
952 if (!lookup.IsProperty()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000953 if (IsContextual(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000954 return ReferenceError("not_defined", name);
955 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000956 LOG(isolate(), SuspectReadEvent(*name, *object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000957 }
958
959 // Update inline cache and stub cache.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000960 if (FLAG_use_ic) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000961 UpdateCaches(&lookup, state, object, name);
962 }
963
964 PropertyAttributes attr;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000965 if (lookup.IsProperty() &&
966 (lookup.type() == INTERCEPTOR || lookup.type() == HANDLER)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000967 // Get the property.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000968 Object* result;
969 { MaybeObject* maybe_result =
970 object->GetProperty(*object, &lookup, *name, &attr);
971 if (!maybe_result->ToObject(&result)) return maybe_result;
972 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000973 // If the property is not present, check if we need to throw an
974 // exception.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000975 if (attr == ABSENT && IsContextual(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000976 return ReferenceError("not_defined", name);
977 }
978 return result;
979 }
980
981 // Get the property.
982 return object->GetProperty(*object, &lookup, *name, &attr);
983}
984
985
986void LoadIC::UpdateCaches(LookupResult* lookup,
987 State state,
988 Handle<Object> object,
989 Handle<String> name) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000990 // Bail out if the result is not cacheable.
991 if (!lookup->IsCacheable()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992
993 // Loading properties from values is not common, so don't try to
994 // deal with non-JS objects here.
995 if (!object->IsJSObject()) return;
996 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
997
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000999
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001000 // Compute the code stub for this load.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001001 MaybeObject* maybe_code = NULL;
1002 Object* code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 if (state == UNINITIALIZED) {
1004 // This is the first time we execute this inline cache.
1005 // Set the target to the pre monomorphic stub to delay
1006 // setting the monomorphic state.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001007 maybe_code = pre_monomorphic_stub();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001008 } else if (!lookup->IsProperty()) {
1009 // Nonexistent property. The result is undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001010 maybe_code = isolate()->stub_cache()->ComputeLoadNonexistent(*name,
1011 *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012 } else {
1013 // Compute monomorphic stub.
1014 switch (lookup->type()) {
1015 case FIELD: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001016 maybe_code = isolate()->stub_cache()->ComputeLoadField(
1017 *name,
1018 *receiver,
1019 lookup->holder(),
1020 lookup->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021 break;
1022 }
1023 case CONSTANT_FUNCTION: {
1024 Object* constant = lookup->GetConstantFunction();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001025 maybe_code = isolate()->stub_cache()->ComputeLoadConstant(
1026 *name, *receiver, lookup->holder(), constant);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001027 break;
1028 }
1029 case NORMAL: {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001030 if (lookup->holder()->IsGlobalObject()) {
1031 GlobalObject* global = GlobalObject::cast(lookup->holder());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001032 JSGlobalPropertyCell* cell =
1033 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001034 maybe_code = isolate()->stub_cache()->ComputeLoadGlobal(*name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001035 *receiver,
1036 global,
1037 cell,
1038 lookup->IsDontDelete());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001039 } else {
1040 // There is only one shared stub for loading normalized
1041 // properties. It does not traverse the prototype chain, so the
1042 // property must be found in the receiver for the stub to be
1043 // applicable.
1044 if (lookup->holder() != *receiver) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001045 maybe_code = isolate()->stub_cache()->ComputeLoadNormal();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001046 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001047 break;
1048 }
1049 case CALLBACKS: {
1050 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
1051 AccessorInfo* callback =
1052 AccessorInfo::cast(lookup->GetCallbackObject());
1053 if (v8::ToCData<Address>(callback->getter()) == 0) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001054 maybe_code = isolate()->stub_cache()->ComputeLoadCallback(
1055 *name, *receiver, lookup->holder(), callback);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056 break;
1057 }
1058 case INTERCEPTOR: {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001059 ASSERT(HasInterceptorGetter(lookup->holder()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 maybe_code = isolate()->stub_cache()->ComputeLoadInterceptor(
1061 *name, *receiver, lookup->holder());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062 break;
1063 }
1064 default:
1065 return;
1066 }
1067 }
1068
1069 // If we're unable to compute the stub (not enough memory left), we
1070 // simply avoid updating the caches.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001071 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072
1073 // Patch the call site depending on the state of the cache.
1074 if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
1075 state == MONOMORPHIC_PROTOTYPE_FAILURE) {
1076 set_target(Code::cast(code));
1077 } else if (state == MONOMORPHIC) {
1078 set_target(megamorphic_stub());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001079 } else if (state == MEGAMORPHIC) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001080 // Cache code holding map should be consistent with
1081 // GenerateMonomorphicCacheProbe.
1082 Map* map = JSObject::cast(object->IsJSObject() ? *object :
1083 object->GetPrototype())->map();
1084
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001085 isolate()->stub_cache()->Set(*name, map, Code::cast(code));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086 }
1087
1088#ifdef DEBUG
1089 TraceIC("LoadIC", name, state, target());
1090#endif
1091}
1092
1093
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001094MaybeObject* KeyedLoadIC::GetElementStubWithoutMapCheck(
1095 bool is_js_array,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001096 JSObject::ElementsKind elements_kind) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001097 return KeyedLoadElementStub(elements_kind).TryGetCode();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001098}
1099
1100
1101MaybeObject* KeyedLoadIC::ConstructMegamorphicStub(
1102 MapList* receiver_maps,
1103 CodeList* targets,
1104 StrictModeFlag strict_mode) {
1105 Object* object;
1106 KeyedLoadStubCompiler compiler;
1107 MaybeObject* maybe_code = compiler.CompileLoadMegamorphic(receiver_maps,
1108 targets);
1109 if (!maybe_code->ToObject(&object)) return maybe_code;
1110 isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
1111 PROFILE(isolate(), CodeCreateEvent(
1112 Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG,
1113 Code::cast(object), 0));
1114 return object;
1115}
1116
1117
lrn@chromium.org303ada72010-10-27 09:33:13 +00001118MaybeObject* KeyedLoadIC::Load(State state,
1119 Handle<Object> object,
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001120 Handle<Object> key,
1121 bool force_generic_stub) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001122 // Check for values that can be converted into a symbol.
1123 // TODO(1295): Remove this code.
1124 HandleScope scope(isolate());
1125 if (key->IsHeapNumber() &&
1126 isnan(HeapNumber::cast(*key)->value())) {
1127 key = isolate()->factory()->nan_symbol();
1128 } else if (key->IsUndefined()) {
1129 key = isolate()->factory()->undefined_symbol();
1130 }
1131
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001132 if (key->IsSymbol()) {
1133 Handle<String> name = Handle<String>::cast(key);
1134
1135 // If the object is undefined or null it's illegal to try to get any
1136 // of its properties; throw a TypeError in that case.
1137 if (object->IsUndefined() || object->IsNull()) {
1138 return TypeError("non_object_property_load", object, name);
1139 }
1140
kasperl@chromium.orgaa95aeb2009-07-28 10:59:50 +00001141 if (FLAG_use_ic) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001142 // TODO(1073): don't ignore the current stub state.
1143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001144 // Use specialized code for getting the length of strings.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001145 if (object->IsString() &&
1146 name->Equals(isolate()->heap()->length_symbol())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147 Handle<String> string = Handle<String>::cast(object);
1148 Object* code = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001149 { MaybeObject* maybe_code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001150 isolate()->stub_cache()->ComputeKeyedLoadStringLength(*name,
1151 *string);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001152 if (!maybe_code->ToObject(&code)) return maybe_code;
1153 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001154 set_target(Code::cast(code));
1155#ifdef DEBUG
1156 TraceIC("KeyedLoadIC", name, state, target());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001157#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001158 return Smi::FromInt(string->length());
1159 }
1160
1161 // Use specialized code for getting the length of arrays.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001162 if (object->IsJSArray() &&
1163 name->Equals(isolate()->heap()->length_symbol())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001164 Handle<JSArray> array = Handle<JSArray>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001165 Object* code;
1166 { MaybeObject* maybe_code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001167 isolate()->stub_cache()->ComputeKeyedLoadArrayLength(*name,
1168 *array);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001169 if (!maybe_code->ToObject(&code)) return maybe_code;
1170 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001171 set_target(Code::cast(code));
1172#ifdef DEBUG
1173 TraceIC("KeyedLoadIC", name, state, target());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001174#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 return JSArray::cast(*object)->length();
1176 }
1177
1178 // Use specialized code for getting prototype of functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001179 if (object->IsJSFunction() &&
1180 name->Equals(isolate()->heap()->prototype_symbol()) &&
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001181 JSFunction::cast(*object)->should_have_prototype()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001182 Handle<JSFunction> function = Handle<JSFunction>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001183 Object* code;
1184 { MaybeObject* maybe_code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001185 isolate()->stub_cache()->ComputeKeyedLoadFunctionPrototype(
1186 *name, *function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001187 if (!maybe_code->ToObject(&code)) return maybe_code;
1188 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189 set_target(Code::cast(code));
1190#ifdef DEBUG
1191 TraceIC("KeyedLoadIC", name, state, target());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001192#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193 return Accessors::FunctionGetPrototype(*object, 0);
1194 }
1195 }
1196
1197 // Check if the name is trivially convertible to an index and get
1198 // the element or char if so.
1199 uint32_t index = 0;
1200 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001201 HandleScope scope(isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001202 // Rewrite to the generic keyed load stub.
1203 if (FLAG_use_ic) set_target(generic_stub());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001204 return Runtime::GetElementOrCharAt(isolate(), object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 }
1206
1207 // Named lookup.
1208 LookupResult lookup;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001209 LookupForRead(*object, *name, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001210
ager@chromium.org5c838252010-02-19 08:53:10 +00001211 // If we did not find a property, check if we need to throw an exception.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001212 if (!lookup.IsProperty() && IsContextual(object)) {
1213 return ReferenceError("not_defined", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 }
1215
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001216 if (FLAG_use_ic) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001217 UpdateCaches(&lookup, state, object, name);
1218 }
1219
1220 PropertyAttributes attr;
ager@chromium.org5c838252010-02-19 08:53:10 +00001221 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 // Get the property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001223 Object* result;
1224 { MaybeObject* maybe_result =
1225 object->GetProperty(*object, &lookup, *name, &attr);
1226 if (!maybe_result->ToObject(&result)) return maybe_result;
1227 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228 // If the property is not present, check if we need to throw an
1229 // exception.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001230 if (attr == ABSENT && IsContextual(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001231 return ReferenceError("not_defined", name);
1232 }
1233 return result;
1234 }
1235
1236 return object->GetProperty(*object, &lookup, *name, &attr);
1237 }
1238
1239 // Do not use ICs for objects that require access checks (including
1240 // the global object).
1241 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
1242
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001243 if (use_ic) {
ager@chromium.org3811b432009-10-28 14:53:37 +00001244 Code* stub = generic_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001245 if (!force_generic_stub) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001246 if (object->IsString() && key->IsNumber()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001247 if (state == UNINITIALIZED) {
1248 stub = string_stub();
1249 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001250 } else if (object->IsJSObject()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001251 JSObject* receiver = JSObject::cast(*object);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001252 Heap* heap = Handle<JSObject>::cast(object)->GetHeap();
1253 Map* elements_map = Handle<JSObject>::cast(object)->elements()->map();
1254 if (elements_map == heap->non_strict_arguments_elements_map()) {
1255 stub = non_strict_arguments_stub();
1256 } else if (receiver->HasIndexedInterceptor()) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001257 stub = indexed_interceptor_stub();
whesse@chromium.org7b260152011-06-20 15:33:18 +00001258 } else if (key->IsSmi() && (target() != non_strict_arguments_stub())) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001259 MaybeObject* maybe_stub = ComputeStub(receiver,
1260 false,
1261 kNonStrictMode,
1262 stub);
1263 stub = maybe_stub->IsFailure() ?
1264 NULL : Code::cast(maybe_stub->ToObjectUnchecked());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001265 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001266 }
1267 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001268 if (stub != NULL) set_target(stub);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001269 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001270
1271#ifdef DEBUG
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001272 TraceIC("KeyedLoadIC", key, state, target());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001273#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274
1275 // Get the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001276 return Runtime::GetObjectProperty(isolate(), object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277}
1278
1279
1280void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
1281 Handle<Object> object, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 // Bail out if we didn't find a result.
ager@chromium.org5c838252010-02-19 08:53:10 +00001283 if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284
1285 if (!object->IsJSObject()) return;
1286 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1287
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001288 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001289
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290 // Compute the code stub for this load.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001291 MaybeObject* maybe_code = NULL;
1292 Object* code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293
1294 if (state == UNINITIALIZED) {
1295 // This is the first time we execute this inline cache.
1296 // Set the target to the pre monomorphic stub to delay
1297 // setting the monomorphic state.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001298 maybe_code = pre_monomorphic_stub();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299 } else {
1300 // Compute a monomorphic stub.
1301 switch (lookup->type()) {
1302 case FIELD: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001303 maybe_code = isolate()->stub_cache()->ComputeKeyedLoadField(
1304 *name, *receiver, lookup->holder(), lookup->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 break;
1306 }
1307 case CONSTANT_FUNCTION: {
1308 Object* constant = lookup->GetConstantFunction();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001309 maybe_code = isolate()->stub_cache()->ComputeKeyedLoadConstant(
1310 *name, *receiver, lookup->holder(), constant);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 break;
1312 }
1313 case CALLBACKS: {
1314 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
1315 AccessorInfo* callback =
1316 AccessorInfo::cast(lookup->GetCallbackObject());
1317 if (v8::ToCData<Address>(callback->getter()) == 0) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 maybe_code = isolate()->stub_cache()->ComputeKeyedLoadCallback(
1319 *name, *receiver, lookup->holder(), callback);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320 break;
1321 }
1322 case INTERCEPTOR: {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001323 ASSERT(HasInterceptorGetter(lookup->holder()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001324 maybe_code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor(
1325 *name, *receiver, lookup->holder());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326 break;
1327 }
1328 default: {
1329 // Always rewrite to the generic case so that we do not
1330 // repeatedly try to rewrite.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001331 maybe_code = generic_stub();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332 break;
1333 }
1334 }
1335 }
1336
1337 // If we're unable to compute the stub (not enough memory left), we
1338 // simply avoid updating the caches.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001339 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340
1341 // Patch the call site depending on the state of the cache. Make
1342 // sure to always rewrite from monomorphic to megamorphic.
1343 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
1344 if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
1345 set_target(Code::cast(code));
1346 } else if (state == MONOMORPHIC) {
1347 set_target(megamorphic_stub());
1348 }
1349
1350#ifdef DEBUG
1351 TraceIC("KeyedLoadIC", name, state, target());
1352#endif
1353}
1354
1355
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001356static bool StoreICableLookup(LookupResult* lookup) {
1357 // Bail out if we didn't find a result.
ager@chromium.org5c838252010-02-19 08:53:10 +00001358 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return false;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001359
1360 // If the property is read-only, we leave the IC in its current
1361 // state.
1362 if (lookup->IsReadOnly()) return false;
1363
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001364 return true;
1365}
1366
1367
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001368static bool LookupForWrite(JSReceiver* receiver,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001369 String* name,
1370 LookupResult* lookup) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001371 receiver->LocalLookup(name, lookup);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001372 if (!StoreICableLookup(lookup)) {
1373 return false;
1374 }
1375
1376 if (lookup->type() == INTERCEPTOR) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001377 JSObject* object = JSObject::cast(receiver);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001378 if (object->GetNamedInterceptor()->setter()->IsUndefined()) {
1379 object->LocalLookupRealNamedProperty(name, lookup);
1380 return StoreICableLookup(lookup);
1381 }
1382 }
1383
1384 return true;
1385}
1386
1387
lrn@chromium.org303ada72010-10-27 09:33:13 +00001388MaybeObject* StoreIC::Store(State state,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001389 StrictModeFlag strict_mode,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001390 Handle<Object> object,
1391 Handle<String> name,
1392 Handle<Object> value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393 // If the object is undefined or null it's illegal to try to set any
1394 // properties on it; throw a TypeError in that case.
1395 if (object->IsUndefined() || object->IsNull()) {
1396 return TypeError("non_object_property_store", object, name);
1397 }
1398
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001399 if (!object->IsJSReceiver()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001400 // The length property of string values is read-only. Throw in strict mode.
1401 if (strict_mode == kStrictMode && object->IsString() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 name->Equals(isolate()->heap()->length_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001403 return TypeError("strict_read_only_property", object, name);
1404 }
1405 // Ignore stores where the receiver is not a JSObject.
1406 return *value;
1407 }
1408
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001409 // Handle proxies.
1410 if (object->IsJSProxy()) {
1411 return JSReceiver::cast(*object)->
1412 SetProperty(*name, *value, NONE, strict_mode);
1413 }
1414
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1416
1417 // Check if the given name is an array index.
1418 uint32_t index;
1419 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001420 HandleScope scope(isolate());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001421 Handle<Object> result = SetElement(receiver, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001422 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423 return *value;
1424 }
1425
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001426 // Use specialized code for setting the length of arrays.
1427 if (receiver->IsJSArray()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001428 && name->Equals(isolate()->heap()->length_symbol())
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001429 && JSArray::cast(*receiver)->AllowsSetElementsLength()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001430#ifdef DEBUG
1431 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
1432#endif
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001433 Builtins::Name target = (strict_mode == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001434 ? Builtins::kStoreIC_ArrayLength_Strict
1435 : Builtins::kStoreIC_ArrayLength;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001436 set_target(isolate()->builtins()->builtin(target));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001437 return receiver->SetProperty(*name, *value, NONE, strict_mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001438 }
1439
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001440 // Lookup the property locally in the receiver.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001441 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
1442 LookupResult lookup;
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00001443
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001444 if (LookupForWrite(*receiver, *name, &lookup)) {
danno@chromium.org160a7b02011-04-18 15:51:38 +00001445 // Generate a stub for this store.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001446 UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001447 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001448 // Strict mode doesn't allow setting non-existent global property
1449 // or an assignment to a read only property.
1450 if (strict_mode == kStrictMode) {
1451 if (lookup.IsFound() && lookup.IsReadOnly()) {
1452 return TypeError("strict_read_only_property", object, name);
1453 } else if (IsContextual(object)) {
1454 return ReferenceError("not_defined", name);
1455 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001456 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001457 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458 }
1459
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001460 if (receiver->IsJSGlobalProxy()) {
1461 // Generate a generic stub that goes to the runtime when we see a global
1462 // proxy as receiver.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 Code* stub = (strict_mode == kStrictMode)
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001464 ? global_proxy_stub_strict()
1465 : global_proxy_stub();
1466 if (target() != stub) {
1467 set_target(stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001468#ifdef DEBUG
1469 TraceIC("StoreIC", name, state, target());
1470#endif
1471 }
1472 }
1473
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001474 // Set the property.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001475 return receiver->SetProperty(*name, *value, NONE, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476}
1477
1478
1479void StoreIC::UpdateCaches(LookupResult* lookup,
1480 State state,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001481 StrictModeFlag strict_mode,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001482 Handle<JSObject> receiver,
1483 Handle<String> name,
1484 Handle<Object> value) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001485 // Skip JSGlobalProxy.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001486 ASSERT(!receiver->IsJSGlobalProxy());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001487
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001488 ASSERT(StoreICableLookup(lookup));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489
1490 // If the property has a non-field type allowing map transitions
1491 // where there is extra room in the object, we leave the IC in its
1492 // current state.
1493 PropertyType type = lookup->type();
1494
1495 // Compute the code stub for this store; used for rewriting to
1496 // monomorphic state and making sure that the code stub is in the
1497 // stub cache.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001498 MaybeObject* maybe_code = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001499 Object* code = NULL;
1500 switch (type) {
1501 case FIELD: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001502 maybe_code = isolate()->stub_cache()->ComputeStoreField(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001503 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504 break;
1505 }
1506 case MAP_TRANSITION: {
1507 if (lookup->GetAttributes() != NONE) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001508 HandleScope scope(isolate());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001509 ASSERT(type == MAP_TRANSITION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510 Handle<Map> transition(lookup->GetTransitionMap());
1511 int index = transition->PropertyIndexFor(*name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001512 maybe_code = isolate()->stub_cache()->ComputeStoreField(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001513 *name, *receiver, index, *transition, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 break;
1515 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001516 case NORMAL: {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001517 if (receiver->IsGlobalObject()) {
1518 // The stub generated for the global object picks the value directly
1519 // from the property cell. So the property must be directly on the
1520 // global object.
1521 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
1522 JSGlobalPropertyCell* cell =
1523 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001524 maybe_code = isolate()->stub_cache()->ComputeStoreGlobal(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001525 *name, *global, cell, strict_mode);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001526 } else {
1527 if (lookup->holder() != *receiver) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001528 maybe_code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001529 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001530 break;
1531 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001532 case CALLBACKS: {
1533 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
1534 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1535 if (v8::ToCData<Address>(callback->setter()) == 0) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001536 maybe_code = isolate()->stub_cache()->ComputeStoreCallback(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001537 *name, *receiver, callback, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001538 break;
1539 }
1540 case INTERCEPTOR: {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001541 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001542 maybe_code = isolate()->stub_cache()->ComputeStoreInterceptor(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001543 *name, *receiver, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544 break;
1545 }
1546 default:
1547 return;
1548 }
1549
1550 // If we're unable to compute the stub (not enough memory left), we
1551 // simply avoid updating the caches.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001552 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001553
1554 // Patch the call site depending on the state of the cache.
1555 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
1556 set_target(Code::cast(code));
1557 } else if (state == MONOMORPHIC) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001558 // Only move to megamorphic if the target changes.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001559 if (target() != Code::cast(code)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001560 set_target((strict_mode == kStrictMode)
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001561 ? megamorphic_stub_strict()
1562 : megamorphic_stub());
1563 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001564 } else if (state == MEGAMORPHIC) {
1565 // Update the stub cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001566 isolate()->stub_cache()->Set(*name,
1567 receiver->map(),
1568 Code::cast(code));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 }
1570
1571#ifdef DEBUG
1572 TraceIC("StoreIC", name, state, target());
1573#endif
1574}
1575
1576
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001577static bool AddOneReceiverMapIfMissing(MapList* receiver_maps,
1578 Map* new_receiver_map) {
1579 for (int current = 0; current < receiver_maps->length(); ++current) {
1580 if (receiver_maps->at(current) == new_receiver_map) {
1581 return false;
1582 }
1583 }
1584 receiver_maps->Add(new_receiver_map);
1585 return true;
1586}
1587
1588
1589void KeyedIC::GetReceiverMapsForStub(Code* stub, MapList* result) {
1590 ASSERT(stub->is_inline_cache_stub());
1591 if (stub == string_stub()) {
1592 return result->Add(isolate()->heap()->string_map());
1593 } else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) {
1594 if (stub->ic_state() == MONOMORPHIC) {
1595 result->Add(Map::cast(stub->FindFirstMap()));
1596 } else {
1597 ASSERT(stub->ic_state() == MEGAMORPHIC);
1598 AssertNoAllocation no_allocation;
1599 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
1600 for (RelocIterator it(stub, mask); !it.done(); it.next()) {
1601 RelocInfo* info = it.rinfo();
1602 Object* object = info->target_object();
1603 ASSERT(object->IsMap());
1604 result->Add(Map::cast(object));
1605 }
1606 }
1607 }
1608}
1609
1610
1611MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
1612 bool is_store,
1613 StrictModeFlag strict_mode,
1614 Code* generic_stub) {
1615 State ic_state = target()->ic_state();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001616 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001617 Code* monomorphic_stub;
1618 MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver,
1619 is_store,
1620 strict_mode,
1621 generic_stub);
1622 if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub;
1623
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001624 return monomorphic_stub;
1625 }
1626 ASSERT(target() != generic_stub);
1627
1628 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1629 // via megamorphic stubs, since they don't have a map in their relocation info
1630 // and so the stubs can't be harvested for the object needed for a map check.
1631 if (target()->type() != NORMAL) {
1632 return generic_stub;
1633 }
1634
1635 // Determine the list of receiver maps that this call site has seen,
1636 // adding the map that was just encountered.
1637 MapList target_receiver_maps;
1638 GetReceiverMapsForStub(target(), &target_receiver_maps);
1639 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map())) {
1640 // If the miss wasn't due to an unseen map, a MEGAMORPHIC stub
1641 // won't help, use the generic stub.
1642 return generic_stub;
1643 }
1644
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001645 // If the maximum number of receiver maps has been exceeded, use the generic
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001646 // version of the IC.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001647 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001648 return generic_stub;
1649 }
1650
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001651 PolymorphicCodeCache* cache = isolate()->heap()->polymorphic_code_cache();
1652 Code::Flags flags = Code::ComputeFlags(this->kind(),
1653 NOT_IN_LOOP,
1654 MEGAMORPHIC,
1655 strict_mode);
1656 Object* maybe_cached_stub = cache->Lookup(&target_receiver_maps, flags);
1657 // If there is a cached stub, use it.
1658 if (!maybe_cached_stub->IsUndefined()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001659 ASSERT(maybe_cached_stub->IsCode());
1660 return Code::cast(maybe_cached_stub);
1661 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001662 // Collect MONOMORPHIC stubs for all target_receiver_maps.
1663 CodeList handler_ics(target_receiver_maps.length());
1664 for (int i = 0; i < target_receiver_maps.length(); ++i) {
1665 Map* receiver_map(target_receiver_maps.at(i));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001666 MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001667 receiver_map, strict_mode);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001668 Code* cached_stub;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001669 if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001670 handler_ics.Add(cached_stub);
1671 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001672 // Build the MEGAMORPHIC stub.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001673 Code* stub;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001674 MaybeObject* maybe_stub = ConstructMegamorphicStub(&target_receiver_maps,
1675 &handler_ics,
1676 strict_mode);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001677 if (!maybe_stub->To(&stub)) return maybe_stub;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001678 MaybeObject* maybe_update = cache->Update(&target_receiver_maps, flags, stub);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001679 if (maybe_update->IsFailure()) return maybe_update;
1680 return stub;
1681}
1682
1683
1684MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
1685 Map* receiver_map,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001686 StrictModeFlag strict_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001687 if ((receiver_map->instance_type() & kNotStringTag) == 0) {
1688 ASSERT(string_stub() != NULL);
1689 return string_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001690 } else {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001691 ASSERT(receiver_map->has_dictionary_elements() ||
1692 receiver_map->has_fast_elements() ||
1693 receiver_map->has_fast_double_elements() ||
1694 receiver_map->has_external_array_elements());
1695 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1696 return GetElementStubWithoutMapCheck(is_js_array,
1697 receiver_map->elements_kind());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001698 }
1699}
1700
1701
1702MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver,
1703 bool is_store,
1704 StrictModeFlag strict_mode,
1705 Code* generic_stub) {
1706 Code* result = NULL;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001707 if (receiver->HasFastElements() ||
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001708 receiver->HasExternalArrayElements() ||
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001709 receiver->HasFastDoubleElements() ||
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001710 receiver->HasDictionaryElements()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001711 MaybeObject* maybe_stub =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001712 isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement(
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001713 receiver, is_store, strict_mode);
1714 if (!maybe_stub->To(&result)) return maybe_stub;
1715 } else {
1716 result = generic_stub;
1717 }
1718 return result;
1719}
1720
1721
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001722MaybeObject* KeyedStoreIC::GetElementStubWithoutMapCheck(
1723 bool is_js_array,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001724 JSObject::ElementsKind elements_kind) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001725 return KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001726}
1727
1728
1729MaybeObject* KeyedStoreIC::ConstructMegamorphicStub(
1730 MapList* receiver_maps,
1731 CodeList* targets,
1732 StrictModeFlag strict_mode) {
1733 Object* object;
1734 KeyedStoreStubCompiler compiler(strict_mode);
1735 MaybeObject* maybe_code = compiler.CompileStoreMegamorphic(receiver_maps,
1736 targets);
1737 if (!maybe_code->ToObject(&object)) return maybe_code;
1738 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
1739 PROFILE(isolate(), CodeCreateEvent(
1740 Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG,
1741 Code::cast(object), 0));
1742 return object;
1743}
1744
1745
lrn@chromium.org303ada72010-10-27 09:33:13 +00001746MaybeObject* KeyedStoreIC::Store(State state,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001747 StrictModeFlag strict_mode,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001748 Handle<Object> object,
1749 Handle<Object> key,
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001750 Handle<Object> value,
1751 bool force_generic) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001752 if (key->IsSymbol()) {
1753 Handle<String> name = Handle<String>::cast(key);
1754
1755 // If the object is undefined or null it's illegal to try to set any
1756 // properties on it; throw a TypeError in that case.
1757 if (object->IsUndefined() || object->IsNull()) {
1758 return TypeError("non_object_property_store", object, name);
1759 }
1760
1761 // Ignore stores where the receiver is not a JSObject.
1762 if (!object->IsJSObject()) return *value;
1763 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1764
1765 // Check if the given name is an array index.
1766 uint32_t index;
1767 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001768 HandleScope scope(isolate());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001769 Handle<Object> result = SetElement(receiver, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001770 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001771 return *value;
1772 }
1773
1774 // Lookup the property locally in the receiver.
1775 LookupResult lookup;
1776 receiver->LocalLookup(*name, &lookup);
1777
1778 // Update inline cache and stub cache.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001779 if (FLAG_use_ic) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001780 UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001781 }
1782
1783 // Set the property.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001784 return receiver->SetProperty(*name, *value, NONE, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001785 }
1786
1787 // Do not use ICs for objects that require access checks (including
1788 // the global object).
1789 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001790 ASSERT(!(use_ic && object->IsJSGlobalProxy()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001791
ager@chromium.org3811b432009-10-28 14:53:37 +00001792 if (use_ic) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001793 Code* stub = (strict_mode == kStrictMode)
1794 ? generic_stub_strict()
1795 : generic_stub();
whesse@chromium.org7b260152011-06-20 15:33:18 +00001796 if (object->IsJSObject()) {
1797 JSObject* receiver = JSObject::cast(*object);
1798 Heap* heap = Handle<JSObject>::cast(object)->GetHeap();
1799 Map* elements_map = Handle<JSObject>::cast(object)->elements()->map();
1800 if (elements_map == heap->non_strict_arguments_elements_map()) {
1801 stub = non_strict_arguments_stub();
1802 } else if (!force_generic) {
1803 if (key->IsSmi() && (target() != non_strict_arguments_stub())) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001804 HandleScope scope(isolate());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001805 MaybeObject* maybe_stub = ComputeStub(receiver,
1806 true,
1807 strict_mode,
1808 stub);
1809 stub = maybe_stub->IsFailure() ?
1810 NULL : Code::cast(maybe_stub->ToObjectUnchecked());
1811 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001812 }
1813 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001814 if (stub != NULL) set_target(stub);
ager@chromium.org3811b432009-10-28 14:53:37 +00001815 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001817#ifdef DEBUG
1818 TraceIC("KeyedStoreIC", key, state, target());
1819#endif
1820
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001821 // Set the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001822 return Runtime::SetObjectProperty(
1823 isolate(), object , key, value, NONE, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001824}
1825
1826
1827void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
1828 State state,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001829 StrictModeFlag strict_mode,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001830 Handle<JSObject> receiver,
1831 Handle<String> name,
1832 Handle<Object> value) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001833 // Skip JSGlobalProxy.
1834 if (receiver->IsJSGlobalProxy()) return;
1835
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001836 // Bail out if we didn't find a result.
ager@chromium.org5c838252010-02-19 08:53:10 +00001837 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001838
1839 // If the property is read-only, we leave the IC in its current
1840 // state.
1841 if (lookup->IsReadOnly()) return;
1842
1843 // If the property has a non-field type allowing map transitions
1844 // where there is extra room in the object, we leave the IC in its
1845 // current state.
1846 PropertyType type = lookup->type();
1847
1848 // Compute the code stub for this store; used for rewriting to
1849 // monomorphic state and making sure that the code stub is in the
1850 // stub cache.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001851 MaybeObject* maybe_code = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001852 Object* code = NULL;
1853
1854 switch (type) {
1855 case FIELD: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856 maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001857 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001858 break;
1859 }
1860 case MAP_TRANSITION: {
1861 if (lookup->GetAttributes() == NONE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 HandleScope scope(isolate());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001863 ASSERT(type == MAP_TRANSITION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001864 Handle<Map> transition(lookup->GetTransitionMap());
1865 int index = transition->PropertyIndexFor(*name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001866 maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001867 *name, *receiver, index, *transition, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001868 break;
1869 }
1870 // fall through.
1871 }
1872 default: {
1873 // Always rewrite to the generic case so that we do not
1874 // repeatedly try to rewrite.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001875 maybe_code = (strict_mode == kStrictMode)
1876 ? generic_stub_strict()
1877 : generic_stub();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001878 break;
1879 }
1880 }
1881
1882 // If we're unable to compute the stub (not enough memory left), we
1883 // simply avoid updating the caches.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001884 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001885
1886 // Patch the call site depending on the state of the cache. Make
1887 // sure to always rewrite from monomorphic to megamorphic.
1888 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
1889 if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
1890 set_target(Code::cast(code));
1891 } else if (state == MONOMORPHIC) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001892 set_target((strict_mode == kStrictMode)
1893 ? megamorphic_stub_strict()
1894 : megamorphic_stub());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001895 }
1896
1897#ifdef DEBUG
1898 TraceIC("KeyedStoreIC", name, state, target());
1899#endif
1900}
1901
1902
1903// ----------------------------------------------------------------------------
1904// Static IC stub generators.
1905//
1906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001907static JSFunction* CompileFunction(Isolate* isolate,
1908 JSFunction* function,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001909 InLoopFlag in_loop) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001910 // Compile now with optimization.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001911 HandleScope scope(isolate);
1912 Handle<JSFunction> function_handle(function, isolate);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001913 if (in_loop == IN_LOOP) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001914 CompileLazyInLoop(function_handle, CLEAR_EXCEPTION);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001915 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001916 CompileLazy(function_handle, CLEAR_EXCEPTION);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001917 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001918 return *function_handle;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001919}
1920
1921
1922// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001923RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001924 NoHandleAllocation na;
1925 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001926 CallIC ic(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001927 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001928 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
1929 MaybeObject* maybe_result = ic.LoadFunction(state,
1930 extra_ic_state,
1931 args.at<Object>(0),
1932 args.at<String>(1));
lrn@chromium.org303ada72010-10-27 09:33:13 +00001933 Object* result;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001934 if (!maybe_result->ToObject(&result)) return maybe_result;
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001935
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001936 // The first time the inline cache is updated may be the first time the
1937 // function it references gets called. If the function was lazily compiled
1938 // then the first call will trigger a compilation. We check for this case
1939 // and we do the compilation immediately, instead of waiting for the stub
1940 // currently attached to the JSFunction object to trigger compilation. We
1941 // do this in the case where we know that the inline cache is inside a loop,
1942 // because then we know that we want to optimize the function.
1943 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
1944 return result;
1945 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001946 return CompileFunction(isolate,
1947 JSFunction::cast(result),
1948 ic.target()->ic_in_loop());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949}
1950
1951
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001952// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001953RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001954 NoHandleAllocation na;
1955 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001956 KeyedCallIC ic(isolate);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001957 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001958 Object* result;
1959 { MaybeObject* maybe_result =
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001960 ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1));
lrn@chromium.org303ada72010-10-27 09:33:13 +00001961 if (!maybe_result->ToObject(&result)) return maybe_result;
1962 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001963
1964 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
1965 return result;
1966 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001967 return CompileFunction(isolate,
1968 JSFunction::cast(result),
1969 ic.target()->ic_in_loop());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001970}
1971
1972
1973// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001974RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001975 NoHandleAllocation na;
1976 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001977 LoadIC ic(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001978 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001979 return ic.Load(state, args.at<Object>(0), args.at<String>(1));
1980}
1981
1982
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001983// Used from ic-<arch>.cc
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001984RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001985 NoHandleAllocation na;
1986 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001987 KeyedLoadIC ic(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001988 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001989 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), false);
1990}
1991
1992
1993RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) {
1994 NoHandleAllocation na;
1995 ASSERT(args.length() == 2);
1996 KeyedLoadIC ic(isolate);
1997 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
1998 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001999}
2000
2001
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002002// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002003RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002004 NoHandleAllocation na;
2005 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002006 StoreIC ic(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002007 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002008 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002009 return ic.Store(state,
2010 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
2011 args.at<Object>(0),
2012 args.at<String>(1),
2013 args.at<Object>(2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014}
2015
2016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002017RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002018 NoHandleAllocation nha;
2019
2020 ASSERT(args.length() == 2);
2021 JSObject* receiver = JSObject::cast(args[0]);
2022 Object* len = args[1];
2023
lrn@chromium.org303ada72010-10-27 09:33:13 +00002024 // The generated code should filter out non-Smis before we get here.
2025 ASSERT(len->IsSmi());
2026
2027 Object* result;
2028 { MaybeObject* maybe_result = receiver->SetElementsLength(len);
2029 if (!maybe_result->ToObject(&result)) return maybe_result;
2030 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002031 return len;
ager@chromium.org5c838252010-02-19 08:53:10 +00002032}
2033
2034
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002035// Extend storage is called in a store inline cache when
2036// it is necessary to extend the properties array of a
2037// JSObject.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002038RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002039 NoHandleAllocation na;
2040 ASSERT(args.length() == 3);
2041
2042 // Convert the parameters
2043 JSObject* object = JSObject::cast(args[0]);
2044 Map* transition = Map::cast(args[1]);
2045 Object* value = args[2];
2046
2047 // Check the object has run out out property space.
2048 ASSERT(object->HasFastProperties());
2049 ASSERT(object->map()->unused_property_fields() == 0);
2050
2051 // Expand the properties array.
2052 FixedArray* old_storage = object->properties();
2053 int new_unused = transition->unused_property_fields();
2054 int new_size = old_storage->length() + new_unused + 1;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002055 Object* result;
2056 { MaybeObject* maybe_result = old_storage->CopySize(new_size);
2057 if (!maybe_result->ToObject(&result)) return maybe_result;
2058 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002059 FixedArray* new_storage = FixedArray::cast(result);
2060 new_storage->set(old_storage->length(), value);
2061
ager@chromium.org32912102009-01-16 10:38:43 +00002062 // Set the new property value and do the map transition.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002063 object->set_properties(new_storage);
2064 object->set_map(transition);
2065
2066 // Return the stored value.
2067 return value;
2068}
2069
2070
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002071// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002072RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073 NoHandleAllocation na;
2074 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002075 KeyedStoreIC ic(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002076 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002077 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2078 return ic.Store(state,
2079 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
2080 args.at<Object>(0),
2081 args.at<Object>(1),
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002082 args.at<Object>(2),
2083 false);
2084}
2085
2086
2087RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) {
2088 NoHandleAllocation na;
2089 ASSERT(args.length() == 3);
2090 KeyedStoreIC ic(isolate);
2091 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2092 Handle<Object> object = args.at<Object>(0);
2093 Handle<Object> key = args.at<Object>(1);
2094 Handle<Object> value = args.at<Object>(2);
2095 StrictModeFlag strict_mode =
2096 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode);
2097 return Runtime::SetObjectProperty(isolate,
2098 object,
2099 key,
2100 value,
2101 NONE,
2102 strict_mode);
2103}
2104
2105
2106RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) {
2107 NoHandleAllocation na;
2108 ASSERT(args.length() == 3);
2109 KeyedStoreIC ic(isolate);
2110 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
2111 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2112 return ic.Store(state,
2113 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
2114 args.at<Object>(0),
2115 args.at<Object>(1),
2116 args.at<Object>(2),
2117 true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002118}
2119
2120
danno@chromium.org40cb8782011-05-25 07:58:50 +00002121void UnaryOpIC::patch(Code* code) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002122 set_target(code);
2123}
2124
2125
danno@chromium.org40cb8782011-05-25 07:58:50 +00002126const char* UnaryOpIC::GetName(TypeInfo type_info) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002127 switch (type_info) {
2128 case UNINITIALIZED: return "Uninitialized";
2129 case SMI: return "Smi";
2130 case HEAP_NUMBER: return "HeapNumbers";
2131 case GENERIC: return "Generic";
2132 default: return "Invalid";
2133 }
2134}
2135
2136
danno@chromium.org40cb8782011-05-25 07:58:50 +00002137UnaryOpIC::State UnaryOpIC::ToState(TypeInfo type_info) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002138 switch (type_info) {
2139 case UNINITIALIZED:
2140 return ::v8::internal::UNINITIALIZED;
2141 case SMI:
2142 case HEAP_NUMBER:
2143 return MONOMORPHIC;
2144 case GENERIC:
2145 return MEGAMORPHIC;
2146 }
2147 UNREACHABLE();
2148 return ::v8::internal::UNINITIALIZED;
2149}
2150
danno@chromium.org40cb8782011-05-25 07:58:50 +00002151UnaryOpIC::TypeInfo UnaryOpIC::GetTypeInfo(Handle<Object> operand) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002152 ::v8::internal::TypeInfo operand_type =
2153 ::v8::internal::TypeInfo::TypeFromValue(operand);
2154 if (operand_type.IsSmi()) {
2155 return SMI;
2156 } else if (operand_type.IsNumber()) {
2157 return HEAP_NUMBER;
2158 } else {
2159 return GENERIC;
2160 }
2161}
2162
2163
danno@chromium.org40cb8782011-05-25 07:58:50 +00002164UnaryOpIC::TypeInfo UnaryOpIC::ComputeNewType(
2165 UnaryOpIC::TypeInfo current_type,
2166 UnaryOpIC::TypeInfo previous_type) {
2167 switch (previous_type) {
2168 case UnaryOpIC::UNINITIALIZED:
2169 return current_type;
2170 case UnaryOpIC::SMI:
2171 return (current_type == UnaryOpIC::GENERIC)
2172 ? UnaryOpIC::GENERIC
2173 : UnaryOpIC::HEAP_NUMBER;
2174 case UnaryOpIC::HEAP_NUMBER:
2175 return UnaryOpIC::GENERIC;
2176 case UnaryOpIC::GENERIC:
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002177 // We should never do patching if we are in GENERIC state.
2178 UNREACHABLE();
danno@chromium.org40cb8782011-05-25 07:58:50 +00002179 return UnaryOpIC::GENERIC;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002180 }
2181 UNREACHABLE();
danno@chromium.org40cb8782011-05-25 07:58:50 +00002182 return UnaryOpIC::GENERIC;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002183}
2184
2185
danno@chromium.org40cb8782011-05-25 07:58:50 +00002186void BinaryOpIC::patch(Code* code) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002187 set_target(code);
2188}
2189
2190
danno@chromium.org40cb8782011-05-25 07:58:50 +00002191const char* BinaryOpIC::GetName(TypeInfo type_info) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002192 switch (type_info) {
2193 case UNINITIALIZED: return "Uninitialized";
2194 case SMI: return "SMI";
2195 case INT32: return "Int32s";
2196 case HEAP_NUMBER: return "HeapNumbers";
lrn@chromium.org7516f052011-03-30 08:52:27 +00002197 case ODDBALL: return "Oddball";
danno@chromium.org160a7b02011-04-18 15:51:38 +00002198 case BOTH_STRING: return "BothStrings";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002199 case STRING: return "Strings";
2200 case GENERIC: return "Generic";
2201 default: return "Invalid";
2202 }
2203}
2204
2205
danno@chromium.org40cb8782011-05-25 07:58:50 +00002206BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002207 switch (type_info) {
2208 case UNINITIALIZED:
2209 return ::v8::internal::UNINITIALIZED;
2210 case SMI:
2211 case INT32:
2212 case HEAP_NUMBER:
lrn@chromium.org7516f052011-03-30 08:52:27 +00002213 case ODDBALL:
danno@chromium.org160a7b02011-04-18 15:51:38 +00002214 case BOTH_STRING:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002215 case STRING:
2216 return MONOMORPHIC;
2217 case GENERIC:
2218 return MEGAMORPHIC;
2219 }
2220 UNREACHABLE();
2221 return ::v8::internal::UNINITIALIZED;
2222}
2223
2224
danno@chromium.org40cb8782011-05-25 07:58:50 +00002225BinaryOpIC::TypeInfo BinaryOpIC::JoinTypes(BinaryOpIC::TypeInfo x,
2226 BinaryOpIC::TypeInfo y) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002227 if (x == UNINITIALIZED) return y;
2228 if (y == UNINITIALIZED) return x;
danno@chromium.org160a7b02011-04-18 15:51:38 +00002229 if (x == y) return x;
2230 if (x == BOTH_STRING && y == STRING) return STRING;
2231 if (x == STRING && y == BOTH_STRING) return STRING;
2232 if (x == STRING || x == BOTH_STRING || y == STRING || y == BOTH_STRING) {
2233 return GENERIC;
2234 }
2235 if (x > y) return x;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002236 return y;
2237}
2238
danno@chromium.org160a7b02011-04-18 15:51:38 +00002239
danno@chromium.org40cb8782011-05-25 07:58:50 +00002240BinaryOpIC::TypeInfo BinaryOpIC::GetTypeInfo(Handle<Object> left,
2241 Handle<Object> right) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002242 ::v8::internal::TypeInfo left_type =
2243 ::v8::internal::TypeInfo::TypeFromValue(left);
2244 ::v8::internal::TypeInfo right_type =
2245 ::v8::internal::TypeInfo::TypeFromValue(right);
2246
2247 if (left_type.IsSmi() && right_type.IsSmi()) {
2248 return SMI;
2249 }
2250
2251 if (left_type.IsInteger32() && right_type.IsInteger32()) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002252 // Platforms with 32-bit Smis have no distinct INT32 type.
2253 if (kSmiValueSize == 32) return SMI;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002254 return INT32;
2255 }
2256
2257 if (left_type.IsNumber() && right_type.IsNumber()) {
2258 return HEAP_NUMBER;
2259 }
2260
danno@chromium.org160a7b02011-04-18 15:51:38 +00002261 // Patching for fast string ADD makes sense even if only one of the
2262 // arguments is a string.
2263 if (left_type.IsString()) {
2264 return right_type.IsString() ? BOTH_STRING : STRING;
2265 } else if (right_type.IsString()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002266 return STRING;
2267 }
2268
lrn@chromium.org7516f052011-03-30 08:52:27 +00002269 // Check for oddball objects.
2270 if (left->IsUndefined() && right->IsNumber()) return ODDBALL;
2271 if (left->IsNumber() && right->IsUndefined()) return ODDBALL;
2272
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002273 return GENERIC;
2274}
2275
2276
danno@chromium.org40cb8782011-05-25 07:58:50 +00002277RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002278 ASSERT(args.length() == 4);
2279
2280 HandleScope scope(isolate);
2281 Handle<Object> operand = args.at<Object>(0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002282 Token::Value op = static_cast<Token::Value>(args.smi_at(1));
2283 UnaryOverwriteMode mode = static_cast<UnaryOverwriteMode>(args.smi_at(2));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002284 UnaryOpIC::TypeInfo previous_type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002285 static_cast<UnaryOpIC::TypeInfo>(args.smi_at(3));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002286
danno@chromium.org40cb8782011-05-25 07:58:50 +00002287 UnaryOpIC::TypeInfo type = UnaryOpIC::GetTypeInfo(operand);
2288 type = UnaryOpIC::ComputeNewType(type, previous_type);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002289
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002290 UnaryOpStub stub(op, mode, type);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002291 Handle<Code> code = stub.GetCode();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002292 if (!code.is_null()) {
2293 if (FLAG_trace_ic) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002294 PrintF("[UnaryOpIC (%s->%s)#%s]\n",
2295 UnaryOpIC::GetName(previous_type),
2296 UnaryOpIC::GetName(type),
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002297 Token::Name(op));
2298 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002299 UnaryOpIC ic(isolate);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002300 ic.patch(*code);
2301 }
2302
2303 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>(
2304 isolate->thread_local_top()->context_->builtins(), isolate);
2305 Object* builtin = NULL; // Initialization calms down the compiler.
2306 switch (op) {
2307 case Token::SUB:
2308 builtin = builtins->javascript_builtin(Builtins::UNARY_MINUS);
2309 break;
2310 case Token::BIT_NOT:
2311 builtin = builtins->javascript_builtin(Builtins::BIT_NOT);
2312 break;
2313 default:
2314 UNREACHABLE();
2315 }
2316
2317 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate);
2318
2319 bool caught_exception;
2320 Handle<Object> result = Execution::Call(builtin_function, operand, 0, NULL,
2321 &caught_exception);
2322 if (caught_exception) {
2323 return Failure::Exception();
2324 }
2325 return *result;
2326}
2327
danno@chromium.org40cb8782011-05-25 07:58:50 +00002328RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002329 ASSERT(args.length() == 5);
2330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002331 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002332 Handle<Object> left = args.at<Object>(0);
2333 Handle<Object> right = args.at<Object>(1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002334 int key = args.smi_at(2);
2335 Token::Value op = static_cast<Token::Value>(args.smi_at(3));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002336 BinaryOpIC::TypeInfo previous_type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002337 static_cast<BinaryOpIC::TypeInfo>(args.smi_at(4));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002338
danno@chromium.org40cb8782011-05-25 07:58:50 +00002339 BinaryOpIC::TypeInfo type = BinaryOpIC::GetTypeInfo(left, right);
2340 type = BinaryOpIC::JoinTypes(type, previous_type);
2341 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED;
2342 if ((type == BinaryOpIC::STRING || type == BinaryOpIC::BOTH_STRING) &&
danno@chromium.org160a7b02011-04-18 15:51:38 +00002343 op != Token::ADD) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002344 type = BinaryOpIC::GENERIC;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002345 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002346 if (type == BinaryOpIC::SMI && previous_type == BinaryOpIC::SMI) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002347 if (op == Token::DIV ||
2348 op == Token::MUL ||
2349 op == Token::SHR ||
2350 kSmiValueSize == 32) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002351 // Arithmetic on two Smi inputs has yielded a heap number.
2352 // That is the only way to get here from the Smi stub.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002353 // With 32-bit Smis, all overflows give heap numbers, but with
2354 // 31-bit Smis, most operations overflow to int32 results.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002355 result_type = BinaryOpIC::HEAP_NUMBER;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002356 } else {
2357 // Other operations on SMIs that overflow yield int32s.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002358 result_type = BinaryOpIC::INT32;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002359 }
2360 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002361 if (type == BinaryOpIC::INT32 && previous_type == BinaryOpIC::INT32) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002362 // We must be here because an operation on two INT32 types overflowed.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002363 result_type = BinaryOpIC::HEAP_NUMBER;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002364 }
2365
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002366 BinaryOpStub stub(key, type, result_type);
2367 Handle<Code> code = stub.GetCode();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002368 if (!code.is_null()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002369 if (FLAG_trace_ic) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002370 PrintF("[BinaryOpIC (%s->(%s->%s))#%s]\n",
2371 BinaryOpIC::GetName(previous_type),
2372 BinaryOpIC::GetName(type),
2373 BinaryOpIC::GetName(result_type),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002374 Token::Name(op));
2375 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002376 BinaryOpIC ic(isolate);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002377 ic.patch(*code);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002378
2379 // Activate inlined smi code.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002380 if (previous_type == BinaryOpIC::UNINITIALIZED) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002381 PatchInlinedSmiCode(ic.address());
2382 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002383 }
2384
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002385 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>(
2386 isolate->thread_local_top()->context_->builtins(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002387 Object* builtin = NULL; // Initialization calms down the compiler.
2388 switch (op) {
2389 case Token::ADD:
2390 builtin = builtins->javascript_builtin(Builtins::ADD);
2391 break;
2392 case Token::SUB:
2393 builtin = builtins->javascript_builtin(Builtins::SUB);
2394 break;
2395 case Token::MUL:
2396 builtin = builtins->javascript_builtin(Builtins::MUL);
2397 break;
2398 case Token::DIV:
2399 builtin = builtins->javascript_builtin(Builtins::DIV);
2400 break;
2401 case Token::MOD:
2402 builtin = builtins->javascript_builtin(Builtins::MOD);
2403 break;
2404 case Token::BIT_AND:
2405 builtin = builtins->javascript_builtin(Builtins::BIT_AND);
2406 break;
2407 case Token::BIT_OR:
2408 builtin = builtins->javascript_builtin(Builtins::BIT_OR);
2409 break;
2410 case Token::BIT_XOR:
2411 builtin = builtins->javascript_builtin(Builtins::BIT_XOR);
2412 break;
2413 case Token::SHR:
2414 builtin = builtins->javascript_builtin(Builtins::SHR);
2415 break;
2416 case Token::SAR:
2417 builtin = builtins->javascript_builtin(Builtins::SAR);
2418 break;
2419 case Token::SHL:
2420 builtin = builtins->javascript_builtin(Builtins::SHL);
2421 break;
2422 default:
2423 UNREACHABLE();
2424 }
2425
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002426 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002427
2428 bool caught_exception;
2429 Object** builtin_args[] = { right.location() };
2430 Handle<Object> result = Execution::Call(builtin_function,
2431 left,
2432 ARRAY_SIZE(builtin_args),
2433 builtin_args,
2434 &caught_exception);
2435 if (caught_exception) {
2436 return Failure::Exception();
2437 }
2438 return *result;
2439}
2440
2441
2442Handle<Code> CompareIC::GetUninitialized(Token::Value op) {
2443 ICCompareStub stub(op, UNINITIALIZED);
2444 return stub.GetCode();
2445}
2446
2447
2448CompareIC::State CompareIC::ComputeState(Code* target) {
2449 int key = target->major_key();
2450 if (key == CodeStub::Compare) return GENERIC;
2451 ASSERT(key == CodeStub::CompareIC);
2452 return static_cast<State>(target->compare_state());
2453}
2454
2455
2456const char* CompareIC::GetStateName(State state) {
2457 switch (state) {
2458 case UNINITIALIZED: return "UNINITIALIZED";
2459 case SMIS: return "SMIS";
2460 case HEAP_NUMBERS: return "HEAP_NUMBERS";
2461 case OBJECTS: return "OBJECTS";
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002462 case SYMBOLS: return "SYMBOLS";
lrn@chromium.org1c092762011-05-09 09:42:16 +00002463 case STRINGS: return "STRINGS";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002464 case GENERIC: return "GENERIC";
2465 default:
2466 UNREACHABLE();
2467 return NULL;
2468 }
2469}
2470
2471
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002472CompareIC::State CompareIC::TargetState(State state,
2473 bool has_inlined_smi_code,
2474 Handle<Object> x,
2475 Handle<Object> y) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002476 if (!has_inlined_smi_code && state != UNINITIALIZED && state != SYMBOLS) {
2477 return GENERIC;
2478 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002479 if (state == UNINITIALIZED && x->IsSmi() && y->IsSmi()) return SMIS;
2480 if ((state == UNINITIALIZED || (state == SMIS && has_inlined_smi_code)) &&
2481 x->IsNumber() && y->IsNumber()) return HEAP_NUMBERS;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002482 if (op_ != Token::EQ && op_ != Token::EQ_STRICT) return GENERIC;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002483 if (state == UNINITIALIZED &&
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002484 x->IsSymbol() && y->IsSymbol()) return SYMBOLS;
2485 if ((state == UNINITIALIZED || state == SYMBOLS) &&
lrn@chromium.org1c092762011-05-09 09:42:16 +00002486 x->IsString() && y->IsString()) return STRINGS;
2487 if (state == UNINITIALIZED &&
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002488 x->IsJSObject() && y->IsJSObject()) return OBJECTS;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002489 return GENERIC;
2490}
2491
2492
2493// Used from ic_<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002494RUNTIME_FUNCTION(Code*, CompareIC_Miss) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002495 NoHandleAllocation na;
2496 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002497 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002498 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
2499 return ic.target();
2500}
2501
2502
ricow@chromium.org9fa09672011-07-25 11:05:35 +00002503RUNTIME_FUNCTION(MaybeObject*, ToBoolean_Patch) {
2504 ASSERT(args.length() == 3);
2505
2506 HandleScope scope(isolate);
2507 Handle<Object> object = args.at<Object>(0);
2508 Register tos = Register::from_code(args.smi_at(1));
2509 ToBooleanStub::Types old_types(args.smi_at(2));
2510
2511 ToBooleanStub::Types new_types(old_types);
2512 bool to_boolean_value = new_types.Record(object);
2513 old_types.TraceTransition(new_types);
2514
2515 ToBooleanStub stub(tos, new_types);
2516 Handle<Code> code = stub.GetCode();
2517 ToBooleanIC ic(isolate);
2518 ic.patch(*code);
2519 return Smi::FromInt(to_boolean_value ? 1 : 0);
2520}
2521
2522
2523void ToBooleanIC::patch(Code* code) {
2524 set_target(code);
2525}
2526
2527
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002528static const Address IC_utilities[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002529#define ADDR(name) FUNCTION_ADDR(name),
2530 IC_UTIL_LIST(ADDR)
2531 NULL
2532#undef ADDR
2533};
2534
2535
2536Address IC::AddressFromUtilityId(IC::UtilityId id) {
2537 return IC_utilities[id];
2538}
2539
2540
2541} } // namespace v8::internal