blob: 83d1c04f5b33303077808121dfe02afa100a55f5 [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();
91 int code_offset = address() - js_code->instruction_start();
92 PrintF("+%d", code_offset);
93 } else {
94 PrintF("<unknown>");
95 }
96 PrintF(" (%c->%c)%s",
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097 TransitionMarkFromState(old_state),
kasperl@chromium.org71affb52009-05-26 05:44:31 +000098 TransitionMarkFromState(new_state),
99 extra_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100 name->Print();
101 PrintF("]\n");
102 }
103}
104#endif
105
106
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000107IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) {
108 ASSERT(isolate == Isolate::Current());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109 // To improve the performance of the (much used) IC code, we unfold
110 // a few levels of the stack frame iteration code. This yields a
111 // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 const Address entry =
113 Isolate::c_entry_fp(isolate->thread_local_top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000114 Address* pc_address =
115 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
116 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
117 // If there's another JavaScript frame on the stack, we need to look
118 // one frame further down the stack to find the frame pointer and
119 // the return address stack slot.
120 if (depth == EXTRA_CALL_FRAME) {
121 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
122 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
123 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
124 }
125#ifdef DEBUG
126 StackFrameIterator it;
127 for (int i = 0; i < depth + 1; i++) it.Advance();
128 StackFrame* frame = it.frame();
129 ASSERT(fp == frame->fp() && pc_address == frame->pc_address());
130#endif
131 fp_ = fp;
132 pc_address_ = pc_address;
133}
134
135
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000136#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000137Address IC::OriginalCodeAddress() {
138 HandleScope scope;
139 // Compute the JavaScript frame for the frame pointer of this IC
140 // structure. We need this to be able to find the function
141 // corresponding to the frame.
142 StackFrameIterator it;
143 while (it.frame()->fp() != this->fp()) it.Advance();
144 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
145 // Find the function on the stack and both the active code for the
146 // function and the original code.
147 JSFunction* function = JSFunction::cast(frame->function());
148 Handle<SharedFunctionInfo> shared(function->shared());
149 Code* code = shared->code();
150 ASSERT(Debug::HasDebugInfo(shared));
151 Code* original_code = Debug::GetDebugInfo(shared)->original_code();
152 ASSERT(original_code->IsCode());
153 // Get the address of the call site in the active code. This is the
154 // place where the call to DebugBreakXXX is and where the IC
155 // normally would be.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000156 Address addr = pc() - Assembler::kCallTargetAddressOffset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000157 // Return the address in the original code. This is the place where
ager@chromium.org32912102009-01-16 10:38:43 +0000158 // the call which has been overwritten by the DebugBreakXXX resides
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159 // and the place where the inline cache system should look.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000160 intptr_t delta =
161 original_code->instruction_start() - code->instruction_start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000162 return addr + delta;
163}
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000164#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000165
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000166
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000167static bool HasNormalObjectsInPrototypeChain(Isolate* isolate,
168 LookupResult* lookup,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000169 Object* receiver) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000170 Object* end = lookup->IsProperty()
171 ? lookup->holder() : isolate->heap()->null_value();
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000172 for (Object* current = receiver;
173 current != end;
174 current = current->GetPrototype()) {
175 if (current->IsJSObject() &&
176 !JSObject::cast(current)->HasFastProperties() &&
177 !current->IsJSGlobalProxy() &&
178 !current->IsJSGlobalObject()) {
179 return true;
180 }
181 }
182
183 return false;
184}
185
186
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000187static bool TryRemoveInvalidPrototypeDependentStub(Code* target,
188 Object* receiver,
189 Object* name) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000190 InlineCacheHolderFlag cache_holder =
191 Code::ExtractCacheHolderFromFlags(target->flags());
192
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000193 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) {
194 // The stub was generated for JSObject but called for non-JSObject.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000195 // IC::GetCodeCacheHolder is not applicable.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000196 return false;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000197 } else if (cache_holder == PROTOTYPE_MAP &&
198 receiver->GetPrototype()->IsNull()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000199 // IC::GetCodeCacheHolder is not applicable.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000200 return false;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000201 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000202 Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203
204 // Decide whether the inline cache failed because of changes to the
205 // receiver itself or changes to one of its prototypes.
206 //
207 // If there are changes to the receiver itself, the map of the
208 // receiver will have changed and the current target will not be in
209 // the receiver map's code cache. Therefore, if the current target
210 // is in the receiver map's code cache, the inline cache failed due
211 // to prototype check failure.
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +0000212 int index = map->IndexInCodeCache(name, target);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000213 if (index >= 0) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000214 map->RemoveFromCodeCache(String::cast(name), target, index);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000215 return true;
216 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000218 return false;
219}
220
221
222IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
223 IC::State state = target->ic_state();
224
225 if (state != MONOMORPHIC || !name->IsString()) return state;
226 if (receiver->IsUndefined() || receiver->IsNull()) return state;
227
228 // For keyed load/store/call, the most likely cause of cache failure is
229 // that the key has changed. We do not distinguish between
230 // prototype and non-prototype failures for keyed access.
231 Code::Kind kind = target->kind();
232 if (kind == Code::KEYED_LOAD_IC ||
233 kind == Code::KEYED_STORE_IC ||
234 kind == Code::KEYED_CALL_IC) {
235 return MONOMORPHIC;
236 }
237
238 // Remove the target from the code cache if it became invalid
239 // because of changes in the prototype chain to avoid hitting it
240 // again.
241 // Call stubs handle this later to allow extra IC state
242 // transitions.
243 if (kind != Code::CALL_IC &&
244 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000245 return MONOMORPHIC_PROTOTYPE_FAILURE;
246 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000247
248 // The builtins object is special. It only changes when JavaScript
249 // builtins are loaded lazily. It is important to keep inline
250 // caches for the builtins object monomorphic. Therefore, if we get
251 // an inline cache miss for the builtins object after lazily loading
ager@chromium.org236ad962008-09-25 09:45:57 +0000252 // JavaScript builtins, we return uninitialized as the state to
253 // force the inline cache back to monomorphic state.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000254 if (receiver->IsJSBuiltinsObject()) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000255 return UNINITIALIZED;
256 }
257
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000258 return MONOMORPHIC;
259}
260
261
ager@chromium.org236ad962008-09-25 09:45:57 +0000262RelocInfo::Mode IC::ComputeMode() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000263 Address addr = address();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000264 Code* code = Code::cast(isolate()->heap()->FindCodeObject(addr));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265 for (RelocIterator it(code, RelocInfo::kCodeTargetMask);
266 !it.done(); it.next()) {
267 RelocInfo* info = it.rinfo();
268 if (info->pc() == addr) return info->rmode();
269 }
270 UNREACHABLE();
ager@chromium.org236ad962008-09-25 09:45:57 +0000271 return RelocInfo::NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000272}
273
274
275Failure* IC::TypeError(const char* type,
276 Handle<Object> object,
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000277 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000278 HandleScope scope(isolate());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000279 Handle<Object> args[2] = { key, object };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000280 Handle<Object> error = isolate()->factory()->NewTypeError(
281 type, HandleVector(args, 2));
282 return isolate()->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000283}
284
285
286Failure* IC::ReferenceError(const char* type, Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000287 HandleScope scope(isolate());
288 Handle<Object> error = isolate()->factory()->NewReferenceError(
289 type, HandleVector(&name, 1));
290 return isolate()->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000291}
292
293
294void IC::Clear(Address address) {
295 Code* target = GetTargetAtAddress(address);
296
297 // Don't clear debug break inline cache as it will remove the break point.
kasper.lund7276f142008-07-30 08:49:36 +0000298 if (target->ic_state() == DEBUG_BREAK) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000299
300 switch (target->kind()) {
301 case Code::LOAD_IC: return LoadIC::Clear(address, target);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000302 case Code::KEYED_LOAD_IC:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000303 return KeyedLoadIC::Clear(address, target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304 case Code::STORE_IC: return StoreIC::Clear(address, target);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000305 case Code::KEYED_STORE_IC:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000306 return KeyedStoreIC::Clear(address, target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000307 case Code::CALL_IC: return CallIC::Clear(address, target);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000308 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000309 case Code::UNARY_OP_IC:
310 case Code::BINARY_OP_IC:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000311 case Code::COMPARE_IC:
312 // Clearing these is tricky and does not
313 // make any performance difference.
314 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000315 default: UNREACHABLE();
316 }
317}
318
319
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000320void CallICBase::Clear(Address address, Code* target) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000321 bool contextual = CallICBase::Contextual::decode(target->extra_ic_state());
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000322 State state = target->ic_state();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000323 if (state == UNINITIALIZED) return;
324 Code* code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325 Isolate::Current()->stub_cache()->FindCallInitialize(
326 target->arguments_count(),
327 target->ic_in_loop(),
danno@chromium.org40cb8782011-05-25 07:58:50 +0000328 contextual ? RelocInfo::CODE_TARGET_CONTEXT : RelocInfo::CODE_TARGET,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000329 target->kind());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330 SetTargetAtAddress(address, code);
331}
332
333
334void KeyedLoadIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000335 if (target->ic_state() == UNINITIALIZED) return;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000336 // Make sure to also clear the map used in inline fast cases. If we
337 // do not clear these maps, cached code can keep objects alive
338 // through the embedded maps.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339 SetTargetAtAddress(address, initialize_stub());
340}
341
342
343void LoadIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000344 if (target->ic_state() == UNINITIALIZED) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345 SetTargetAtAddress(address, initialize_stub());
346}
347
348
349void StoreIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000350 if (target->ic_state() == UNINITIALIZED) return;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000351 SetTargetAtAddress(address,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000352 (target->extra_ic_state() == kStrictMode)
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000353 ? initialize_stub_strict()
354 : initialize_stub());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355}
356
357
358void KeyedStoreIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000359 if (target->ic_state() == UNINITIALIZED) return;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000360 SetTargetAtAddress(address,
361 (target->extra_ic_state() == kStrictMode)
362 ? initialize_stub_strict()
363 : initialize_stub());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364}
365
366
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000367static bool HasInterceptorGetter(JSObject* object) {
368 return !object->GetNamedInterceptor()->getter()->IsUndefined();
369}
370
371
372static void LookupForRead(Object* object,
373 String* name,
374 LookupResult* lookup) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000375 AssertNoAllocation no_gc; // pointers must stay valid
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000376
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000377 // Skip all the objects with named interceptors, but
378 // without actual getter.
379 while (true) {
380 object->Lookup(name, lookup);
381 // Besides normal conditions (property not found or it's not
ager@chromium.org5c838252010-02-19 08:53:10 +0000382 // an interceptor), bail out if lookup is not cacheable: we won't
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000383 // be able to IC it anyway and regular lookup should work fine.
ager@chromium.org5c838252010-02-19 08:53:10 +0000384 if (!lookup->IsFound()
385 || (lookup->type() != INTERCEPTOR)
386 || !lookup->IsCacheable()) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000387 return;
388 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000389
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000390 JSObject* holder = lookup->holder();
391 if (HasInterceptorGetter(holder)) {
392 return;
393 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000394
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000395 holder->LocalLookupRealNamedProperty(name, lookup);
ager@chromium.org5c838252010-02-19 08:53:10 +0000396 if (lookup->IsProperty()) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000397 ASSERT(lookup->type() != INTERCEPTOR);
398 return;
399 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000400
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000401 Object* proto = holder->GetPrototype();
402 if (proto->IsNull()) {
403 lookup->NotFound();
404 return;
405 }
406
407 object = proto;
408 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000409}
410
411
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000412Object* CallICBase::TryCallAsFunction(Object* object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 HandleScope scope(isolate());
414 Handle<Object> target(object, isolate());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000415 Handle<Object> delegate = Execution::GetFunctionDelegate(target);
416
417 if (delegate->IsJSFunction()) {
418 // Patch the receiver and use the delegate as the function to
419 // invoke. This is used for invoking objects as if they were
420 // functions.
421 const int argc = this->target()->arguments_count();
422 StackFrameLocator locator;
423 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
424 int index = frame->ComputeExpressionsCount() - (argc + 1);
425 frame->SetExpression(index, *target);
426 }
427
428 return *delegate;
429}
430
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000431
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000432void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee,
433 Handle<Object> object) {
434 if (callee->IsJSFunction()) {
435 Handle<JSFunction> function = Handle<JSFunction>::cast(callee);
436 if (function->shared()->strict_mode() || function->IsBuiltin()) {
437 // Do not wrap receiver for strict mode functions or for builtins.
438 return;
439 }
440 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000441
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000442 // And only wrap string, number or boolean.
443 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
444 // Change the receiver to the result of calling ToObject on it.
445 const int argc = this->target()->arguments_count();
446 StackFrameLocator locator;
447 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
448 int index = frame->ComputeExpressionsCount() - (argc + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 frame->SetExpression(index, *isolate()->factory()->ToObject(object));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000450 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000451}
452
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000453
lrn@chromium.org303ada72010-10-27 09:33:13 +0000454MaybeObject* CallICBase::LoadFunction(State state,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000455 Code::ExtraICState extra_ic_state,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000456 Handle<Object> object,
457 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000458 // If the object is undefined or null it's illegal to try to get any
459 // of its properties; throw a TypeError in that case.
460 if (object->IsUndefined() || object->IsNull()) {
461 return TypeError("non_object_property_call", object, name);
462 }
463
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000464 // Check if the name is trivially convertible to an index and get
465 // the element if so.
466 uint32_t index;
467 if (name->AsArrayIndex(&index)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000468 Object* result;
469 { MaybeObject* maybe_result = object->GetElement(index);
470 if (!maybe_result->ToObject(&result)) return maybe_result;
471 }
472
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000473 if (result->IsJSFunction()) return result;
474
475 // Try to find a suitable function delegate for the object at hand.
476 result = TryCallAsFunction(result);
477 if (result->IsJSFunction()) return result;
478
479 // Otherwise, it will fail in the lookup step.
480 }
481
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000482 // Lookup the property in the object.
483 LookupResult lookup;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000484 LookupForRead(*object, *name, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485
ager@chromium.org5c838252010-02-19 08:53:10 +0000486 if (!lookup.IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487 // If the object does not have the requested property, check which
488 // exception we need to throw.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000489 if (IsContextual(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000490 return ReferenceError("not_defined", name);
491 }
492 return TypeError("undefined_method", object, name);
493 }
494
495 // Lookup is valid: Update inline cache and stub cache.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000496 if (FLAG_use_ic) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000497 UpdateCaches(&lookup, state, extra_ic_state, object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000498 }
499
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000500 // Get the property.
501 PropertyAttributes attr;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000502 Object* result;
503 { MaybeObject* maybe_result =
504 object->GetProperty(*object, &lookup, *name, &attr);
505 if (!maybe_result->ToObject(&result)) return maybe_result;
506 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000507
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508 if (lookup.type() == INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509 // If the object does not have the requested property, check which
510 // exception we need to throw.
511 if (attr == ABSENT) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000512 if (IsContextual(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000513 return ReferenceError("not_defined", name);
514 }
515 return TypeError("undefined_method", object, name);
516 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000517 }
518
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000519 ASSERT(!result->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000520
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 HandleScope scope(isolate());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000522 // Wrap result in a handle because ReceiverToObjectIfRequired may allocate
523 // new object and cause GC.
524 Handle<Object> result_handle(result);
525 // Make receiver an object if the callee requires it. Strict mode or builtin
526 // functions do not wrap the receiver, non-strict functions and objects
527 // called as functions do.
528 ReceiverToObjectIfRequired(result_handle, object);
529
530 if (result_handle->IsJSFunction()) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000531#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000532 // Handle stepping into a function if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 Debug* debug = isolate()->debug();
534 if (debug->StepInActive()) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000535 // Protect the result in a handle as the debugger can allocate and might
536 // cause GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000537 Handle<JSFunction> function(JSFunction::cast(*result_handle), isolate());
538 debug->HandleStepIn(function, object, fp(), false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000539 return *function;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000541#endif
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000542
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000543 return *result_handle;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544 }
545
546 // Try to find a suitable function delegate for the object at hand.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000547 result_handle = Handle<Object>(TryCallAsFunction(*result_handle));
548 if (result_handle->IsJSFunction()) return *result_handle;
549
550 return TypeError("property_not_function", object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551}
552
553
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000554bool CallICBase::TryUpdateExtraICState(LookupResult* lookup,
555 Handle<Object> object,
556 Code::ExtraICState* extra_ic_state) {
557 ASSERT(kind_ == Code::CALL_IC);
558 if (lookup->type() != CONSTANT_FUNCTION) return false;
559 JSFunction* function = lookup->GetConstantFunction();
560 if (!function->shared()->HasBuiltinFunctionId()) return false;
561
562 // Fetch the arguments passed to the called function.
563 const int argc = target()->arguments_count();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000565 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
566 Arguments args(argc + 1,
567 &Memory::Object_at(fp +
568 StandardFrameConstants::kCallerSPOffset +
569 argc * kPointerSize));
570 switch (function->shared()->builtin_function_id()) {
571 case kStringCharCodeAt:
572 case kStringCharAt:
573 if (object->IsString()) {
574 String* string = String::cast(*object);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000575 // Check there's the right string value or wrapper in the receiver slot.
576 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000577 // If we're in the default (fastest) state and the index is
578 // out of bounds, update the state to record this fact.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000579 if (StringStubState::decode(*extra_ic_state) == DEFAULT_STRING_STUB &&
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000580 argc >= 1 && args[1]->IsNumber()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000581 double index = DoubleToInteger(args.number_at(1));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000582 if (index < 0 || index >= string->length()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000583 *extra_ic_state =
584 StringStubState::update(*extra_ic_state,
585 STRING_INDEX_OUT_OF_BOUNDS);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000586 return true;
587 }
588 }
589 }
590 break;
591 default:
592 return false;
593 }
594 return false;
595}
596
597
598MaybeObject* CallICBase::ComputeMonomorphicStub(
599 LookupResult* lookup,
600 State state,
601 Code::ExtraICState extra_ic_state,
602 Handle<Object> object,
603 Handle<String> name) {
604 int argc = target()->arguments_count();
605 InLoopFlag in_loop = target()->ic_in_loop();
606 MaybeObject* maybe_code = NULL;
607 switch (lookup->type()) {
608 case FIELD: {
609 int index = lookup->GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000610 maybe_code = isolate()->stub_cache()->ComputeCallField(argc,
611 in_loop,
612 kind_,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000613 extra_ic_state,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 *name,
615 *object,
616 lookup->holder(),
617 index);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000618 break;
619 }
620 case CONSTANT_FUNCTION: {
621 // Get the constant function and compute the code stub for this
622 // call; used for rewriting to monomorphic state and making sure
623 // that the code stub is in the stub cache.
624 JSFunction* function = lookup->GetConstantFunction();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000625 maybe_code =
626 isolate()->stub_cache()->ComputeCallConstant(argc,
627 in_loop,
628 kind_,
629 extra_ic_state,
630 *name,
631 *object,
632 lookup->holder(),
633 function);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000634 break;
635 }
636 case NORMAL: {
637 if (!object->IsJSObject()) return NULL;
638 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
639
640 if (lookup->holder()->IsGlobalObject()) {
641 GlobalObject* global = GlobalObject::cast(lookup->holder());
642 JSGlobalPropertyCell* cell =
643 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
644 if (!cell->value()->IsJSFunction()) return NULL;
645 JSFunction* function = JSFunction::cast(cell->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000646 maybe_code = isolate()->stub_cache()->ComputeCallGlobal(argc,
647 in_loop,
648 kind_,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000649 extra_ic_state,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000650 *name,
651 *receiver,
652 global,
653 cell,
654 function);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000655 } else {
656 // There is only one shared stub for calling normalized
657 // properties. It does not traverse the prototype chain, so the
658 // property must be found in the receiver for the stub to be
659 // applicable.
660 if (lookup->holder() != *receiver) return NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000661 maybe_code = isolate()->stub_cache()->ComputeCallNormal(argc,
662 in_loop,
663 kind_,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000664 extra_ic_state,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000665 *name,
666 *receiver);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000667 }
668 break;
669 }
670 case INTERCEPTOR: {
671 ASSERT(HasInterceptorGetter(lookup->holder()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000672 maybe_code = isolate()->stub_cache()->ComputeCallInterceptor(
673 argc,
674 kind_,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000675 extra_ic_state,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000676 *name,
677 *object,
678 lookup->holder());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000679 break;
680 }
681 default:
682 maybe_code = NULL;
683 break;
684 }
685 return maybe_code;
686}
687
688
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000689void CallICBase::UpdateCaches(LookupResult* lookup,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000690 State state,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000691 Code::ExtraICState extra_ic_state,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000692 Handle<Object> object,
693 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000694 // Bail out if we didn't find a result.
ager@chromium.org5c838252010-02-19 08:53:10 +0000695 if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000697 if (lookup->holder() != *object &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000698 HasNormalObjectsInPrototypeChain(
699 isolate(), lookup, object->GetPrototype())) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000700 // Suppress optimization for prototype chains with slow properties objects
701 // in the middle.
702 return;
703 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000704
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000705 // Compute the number of arguments.
706 int argc = target()->arguments_count();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000707 InLoopFlag in_loop = target()->ic_in_loop();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000708 MaybeObject* maybe_code = NULL;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000709 bool had_proto_failure = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000710 if (state == UNINITIALIZED) {
711 // This is the first time we execute this inline cache.
712 // Set the target to the pre monomorphic stub to delay
713 // setting the monomorphic state.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000714 maybe_code =
715 isolate()->stub_cache()->ComputeCallPreMonomorphic(argc,
716 in_loop,
717 kind_,
718 extra_ic_state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000719 } else if (state == MONOMORPHIC) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000720 if (kind_ == Code::CALL_IC &&
721 TryUpdateExtraICState(lookup, object, &extra_ic_state)) {
722 maybe_code = ComputeMonomorphicStub(lookup,
723 state,
724 extra_ic_state,
725 object,
726 name);
727 } else if (kind_ == Code::CALL_IC &&
728 TryRemoveInvalidPrototypeDependentStub(target(),
729 *object,
730 *name)) {
731 had_proto_failure = true;
732 maybe_code = ComputeMonomorphicStub(lookup,
733 state,
734 extra_ic_state,
735 object,
736 name);
737 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000738 maybe_code =
739 isolate()->stub_cache()->ComputeCallMegamorphic(argc,
740 in_loop,
741 kind_,
742 extra_ic_state);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000744 } else {
745 maybe_code = ComputeMonomorphicStub(lookup,
746 state,
747 extra_ic_state,
748 object,
749 name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000750 }
751
752 // If we're unable to compute the stub (not enough memory left), we
753 // simply avoid updating the caches.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000754 Object* code;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000755 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000756
757 // Patch the call site depending on the state of the cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000758 if (state == UNINITIALIZED ||
759 state == PREMONOMORPHIC ||
760 state == MONOMORPHIC ||
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000761 state == MONOMORPHIC_PROTOTYPE_FAILURE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000762 set_target(Code::cast(code));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000763 } else if (state == MEGAMORPHIC) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000764 // Cache code holding map should be consistent with
765 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub.
766 Map* map = JSObject::cast(object->IsJSObject() ? *object :
767 object->GetPrototype())->map();
768
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000769 // Update the stub cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000770 isolate()->stub_cache()->Set(*name, map, Code::cast(code));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771 }
772
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000773 USE(had_proto_failure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000774#ifdef DEBUG
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000775 if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000776 TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
777 name, state, target(), in_loop ? " (in-loop)" : "");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778#endif
779}
780
781
lrn@chromium.org303ada72010-10-27 09:33:13 +0000782MaybeObject* KeyedCallIC::LoadFunction(State state,
783 Handle<Object> object,
784 Handle<Object> key) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000785 if (key->IsSymbol()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000786 return CallICBase::LoadFunction(state,
787 Code::kNoExtraICState,
788 object,
789 Handle<String>::cast(key));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000790 }
791
792 if (object->IsUndefined() || object->IsNull()) {
793 return TypeError("non_object_property_call", object, key);
794 }
795
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000796 if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) {
797 int argc = target()->arguments_count();
798 InLoopFlag in_loop = target()->ic_in_loop();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000799 MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(
danno@chromium.org40cb8782011-05-25 07:58:50 +0000800 argc, in_loop, Code::KEYED_CALL_IC, Code::kNoExtraICState);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000801 Object* code;
802 if (maybe_code->ToObject(&code)) {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000803 set_target(Code::cast(code));
804#ifdef DEBUG
805 TraceIC(
806 "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : "");
807#endif
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000808 }
809 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000810
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000811 HandleScope scope(isolate());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000812 Handle<Object> result = GetProperty(object, key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000813 RETURN_IF_EMPTY_HANDLE(isolate(), result);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000814
815 // Make receiver an object if the callee requires it. Strict mode or builtin
816 // functions do not wrap the receiver, non-strict functions and objects
817 // called as functions do.
818 ReceiverToObjectIfRequired(result, object);
819
820 if (result->IsJSFunction()) return *result;
821 result = Handle<Object>(TryCallAsFunction(*result));
822 if (result->IsJSFunction()) return *result;
823
824 return TypeError("property_not_function", object, key);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000825}
826
827
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000828#ifdef DEBUG
829#define TRACE_IC_NAMED(msg, name) \
830 if (FLAG_trace_ic) PrintF(msg, *(name)->ToCString())
831#else
832#define TRACE_IC_NAMED(msg, name)
833#endif
834
835
lrn@chromium.org303ada72010-10-27 09:33:13 +0000836MaybeObject* LoadIC::Load(State state,
837 Handle<Object> object,
838 Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839 // If the object is undefined or null it's illegal to try to get any
840 // of its properties; throw a TypeError in that case.
841 if (object->IsUndefined() || object->IsNull()) {
842 return TypeError("non_object_property_load", object, name);
843 }
844
845 if (FLAG_use_ic) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000846 Code* non_monomorphic_stub =
847 (state == UNINITIALIZED) ? pre_monomorphic_stub() : megamorphic_stub();
848
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000849 // Use specialized code for getting the length of strings and
850 // string wrapper objects. The length property of string wrapper
851 // objects is read-only and therefore always returns the length of
852 // the underlying string value. See ECMA-262 15.5.5.1.
853 if ((object->IsString() || object->IsStringWrapper()) &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 name->Equals(isolate()->heap()->length_symbol())) {
855 HandleScope scope(isolate());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000856#ifdef DEBUG
857 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
858#endif
859 if (state == PREMONOMORPHIC) {
860 if (object->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 set_target(isolate()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000862 Builtins::kLoadIC_StringLength));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000863 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000864 set_target(isolate()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000865 Builtins::kLoadIC_StringWrapperLength));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000866 }
867 } else if (state == MONOMORPHIC && object->IsStringWrapper()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000868 set_target(isolate()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000869 Builtins::kLoadIC_StringWrapperLength));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000870 } else {
871 set_target(non_monomorphic_stub);
872 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000873 // Get the string if we have a string wrapper object.
874 if (object->IsJSValue()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000875 object = Handle<Object>(Handle<JSValue>::cast(object)->value(),
876 isolate());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000877 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000878 return Smi::FromInt(String::cast(*object)->length());
879 }
880
881 // Use specialized code for getting the length of arrays.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000882 if (object->IsJSArray() &&
883 name->Equals(isolate()->heap()->length_symbol())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000884#ifdef DEBUG
885 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
886#endif
ager@chromium.org378b34e2011-01-28 08:04:38 +0000887 if (state == PREMONOMORPHIC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000888 set_target(isolate()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000889 Builtins::kLoadIC_ArrayLength));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000890 } else {
891 set_target(non_monomorphic_stub);
892 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000893 return JSArray::cast(*object)->length();
894 }
895
896 // Use specialized code for getting prototype of functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000897 if (object->IsJSFunction() &&
898 name->Equals(isolate()->heap()->prototype_symbol()) &&
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000899 JSFunction::cast(*object)->should_have_prototype()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000900#ifdef DEBUG
901 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
902#endif
ager@chromium.org378b34e2011-01-28 08:04:38 +0000903 if (state == PREMONOMORPHIC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000904 set_target(isolate()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000905 Builtins::kLoadIC_FunctionPrototype));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000906 } else {
907 set_target(non_monomorphic_stub);
908 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000909 return Accessors::FunctionGetPrototype(*object, 0);
910 }
911 }
912
913 // Check if the name is trivially convertible to an index and get
914 // the element if so.
915 uint32_t index;
916 if (name->AsArrayIndex(&index)) return object->GetElement(index);
917
918 // Named lookup in the object.
919 LookupResult lookup;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000920 LookupForRead(*object, *name, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000921
ager@chromium.org5c838252010-02-19 08:53:10 +0000922 // If we did not find a property, check if we need to throw an exception.
923 if (!lookup.IsProperty()) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000924 if (FLAG_strict || IsContextual(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 return ReferenceError("not_defined", name);
926 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000927 LOG(isolate(), SuspectReadEvent(*name, *object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000928 }
929
930 // Update inline cache and stub cache.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000931 if (FLAG_use_ic) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000932 UpdateCaches(&lookup, state, object, name);
933 }
934
935 PropertyAttributes attr;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000936 if (lookup.IsProperty() &&
937 (lookup.type() == INTERCEPTOR || lookup.type() == HANDLER)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938 // Get the property.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000939 Object* result;
940 { MaybeObject* maybe_result =
941 object->GetProperty(*object, &lookup, *name, &attr);
942 if (!maybe_result->ToObject(&result)) return maybe_result;
943 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000944 // If the property is not present, check if we need to throw an
945 // exception.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000946 if (attr == ABSENT && IsContextual(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000947 return ReferenceError("not_defined", name);
948 }
949 return result;
950 }
951
952 // Get the property.
953 return object->GetProperty(*object, &lookup, *name, &attr);
954}
955
956
957void LoadIC::UpdateCaches(LookupResult* lookup,
958 State state,
959 Handle<Object> object,
960 Handle<String> name) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000961 // Bail out if the result is not cacheable.
962 if (!lookup->IsCacheable()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000963
964 // Loading properties from values is not common, so don't try to
965 // deal with non-JS objects here.
966 if (!object->IsJSObject()) return;
967 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
968
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000970
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000971 // Compute the code stub for this load.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000972 MaybeObject* maybe_code = NULL;
973 Object* code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000974 if (state == UNINITIALIZED) {
975 // This is the first time we execute this inline cache.
976 // Set the target to the pre monomorphic stub to delay
977 // setting the monomorphic state.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000978 maybe_code = pre_monomorphic_stub();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000979 } else if (!lookup->IsProperty()) {
980 // Nonexistent property. The result is undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000981 maybe_code = isolate()->stub_cache()->ComputeLoadNonexistent(*name,
982 *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000983 } else {
984 // Compute monomorphic stub.
985 switch (lookup->type()) {
986 case FIELD: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000987 maybe_code = isolate()->stub_cache()->ComputeLoadField(
988 *name,
989 *receiver,
990 lookup->holder(),
991 lookup->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992 break;
993 }
994 case CONSTANT_FUNCTION: {
995 Object* constant = lookup->GetConstantFunction();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000996 maybe_code = isolate()->stub_cache()->ComputeLoadConstant(
997 *name, *receiver, lookup->holder(), constant);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 break;
999 }
1000 case NORMAL: {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001001 if (lookup->holder()->IsGlobalObject()) {
1002 GlobalObject* global = GlobalObject::cast(lookup->holder());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001003 JSGlobalPropertyCell* cell =
1004 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001005 maybe_code = isolate()->stub_cache()->ComputeLoadGlobal(*name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001006 *receiver,
1007 global,
1008 cell,
1009 lookup->IsDontDelete());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001010 } else {
1011 // There is only one shared stub for loading normalized
1012 // properties. It does not traverse the prototype chain, so the
1013 // property must be found in the receiver for the stub to be
1014 // applicable.
1015 if (lookup->holder() != *receiver) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001016 maybe_code = isolate()->stub_cache()->ComputeLoadNormal();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001017 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018 break;
1019 }
1020 case CALLBACKS: {
1021 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
1022 AccessorInfo* callback =
1023 AccessorInfo::cast(lookup->GetCallbackObject());
1024 if (v8::ToCData<Address>(callback->getter()) == 0) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001025 maybe_code = isolate()->stub_cache()->ComputeLoadCallback(
1026 *name, *receiver, lookup->holder(), callback);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001027 break;
1028 }
1029 case INTERCEPTOR: {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001030 ASSERT(HasInterceptorGetter(lookup->holder()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001031 maybe_code = isolate()->stub_cache()->ComputeLoadInterceptor(
1032 *name, *receiver, lookup->holder());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001033 break;
1034 }
1035 default:
1036 return;
1037 }
1038 }
1039
1040 // If we're unable to compute the stub (not enough memory left), we
1041 // simply avoid updating the caches.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001042 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001043
1044 // Patch the call site depending on the state of the cache.
1045 if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
1046 state == MONOMORPHIC_PROTOTYPE_FAILURE) {
1047 set_target(Code::cast(code));
1048 } else if (state == MONOMORPHIC) {
1049 set_target(megamorphic_stub());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001050 } else if (state == MEGAMORPHIC) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001051 // Cache code holding map should be consistent with
1052 // GenerateMonomorphicCacheProbe.
1053 Map* map = JSObject::cast(object->IsJSObject() ? *object :
1054 object->GetPrototype())->map();
1055
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001056 isolate()->stub_cache()->Set(*name, map, Code::cast(code));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057 }
1058
1059#ifdef DEBUG
1060 TraceIC("LoadIC", name, state, target());
1061#endif
1062}
1063
1064
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001065String* KeyedLoadIC::GetStubNameForCache(IC::State ic_state) {
1066 if (ic_state == MONOMORPHIC) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001067 return isolate()->heap()->KeyedLoadElementMonomorphic_symbol();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001068 } else {
1069 ASSERT(ic_state == MEGAMORPHIC);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001070 return isolate()->heap()->KeyedLoadElementPolymorphic_symbol();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001071 }
1072}
1073
1074
1075MaybeObject* KeyedLoadIC::GetFastElementStubWithoutMapCheck(
1076 bool is_js_array) {
1077 return KeyedLoadFastElementStub().TryGetCode();
1078}
1079
1080
1081MaybeObject* KeyedLoadIC::GetExternalArrayStubWithoutMapCheck(
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001082 JSObject::ElementsKind elements_kind) {
1083 return KeyedLoadExternalArrayStub(elements_kind).TryGetCode();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001084}
1085
1086
1087MaybeObject* KeyedLoadIC::ConstructMegamorphicStub(
1088 MapList* receiver_maps,
1089 CodeList* targets,
1090 StrictModeFlag strict_mode) {
1091 Object* object;
1092 KeyedLoadStubCompiler compiler;
1093 MaybeObject* maybe_code = compiler.CompileLoadMegamorphic(receiver_maps,
1094 targets);
1095 if (!maybe_code->ToObject(&object)) return maybe_code;
1096 isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
1097 PROFILE(isolate(), CodeCreateEvent(
1098 Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG,
1099 Code::cast(object), 0));
1100 return object;
1101}
1102
1103
lrn@chromium.org303ada72010-10-27 09:33:13 +00001104MaybeObject* KeyedLoadIC::Load(State state,
1105 Handle<Object> object,
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001106 Handle<Object> key,
1107 bool force_generic_stub) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001108 // Check for values that can be converted into a symbol.
1109 // TODO(1295): Remove this code.
1110 HandleScope scope(isolate());
1111 if (key->IsHeapNumber() &&
1112 isnan(HeapNumber::cast(*key)->value())) {
1113 key = isolate()->factory()->nan_symbol();
1114 } else if (key->IsUndefined()) {
1115 key = isolate()->factory()->undefined_symbol();
1116 }
1117
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118 if (key->IsSymbol()) {
1119 Handle<String> name = Handle<String>::cast(key);
1120
1121 // If the object is undefined or null it's illegal to try to get any
1122 // of its properties; throw a TypeError in that case.
1123 if (object->IsUndefined() || object->IsNull()) {
1124 return TypeError("non_object_property_load", object, name);
1125 }
1126
kasperl@chromium.orgaa95aeb2009-07-28 10:59:50 +00001127 if (FLAG_use_ic) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001128 // TODO(1073): don't ignore the current stub state.
1129
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001130 // Use specialized code for getting the length of strings.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001131 if (object->IsString() &&
1132 name->Equals(isolate()->heap()->length_symbol())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001133 Handle<String> string = Handle<String>::cast(object);
1134 Object* code = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001135 { MaybeObject* maybe_code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001136 isolate()->stub_cache()->ComputeKeyedLoadStringLength(*name,
1137 *string);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001138 if (!maybe_code->ToObject(&code)) return maybe_code;
1139 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001140 set_target(Code::cast(code));
1141#ifdef DEBUG
1142 TraceIC("KeyedLoadIC", name, state, target());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001143#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001144 return Smi::FromInt(string->length());
1145 }
1146
1147 // Use specialized code for getting the length of arrays.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 if (object->IsJSArray() &&
1149 name->Equals(isolate()->heap()->length_symbol())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001150 Handle<JSArray> array = Handle<JSArray>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001151 Object* code;
1152 { MaybeObject* maybe_code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001153 isolate()->stub_cache()->ComputeKeyedLoadArrayLength(*name,
1154 *array);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001155 if (!maybe_code->ToObject(&code)) return maybe_code;
1156 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157 set_target(Code::cast(code));
1158#ifdef DEBUG
1159 TraceIC("KeyedLoadIC", name, state, target());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001160#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161 return JSArray::cast(*object)->length();
1162 }
1163
1164 // Use specialized code for getting prototype of functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001165 if (object->IsJSFunction() &&
1166 name->Equals(isolate()->heap()->prototype_symbol()) &&
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001167 JSFunction::cast(*object)->should_have_prototype()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 Handle<JSFunction> function = Handle<JSFunction>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001169 Object* code;
1170 { MaybeObject* maybe_code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001171 isolate()->stub_cache()->ComputeKeyedLoadFunctionPrototype(
1172 *name, *function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001173 if (!maybe_code->ToObject(&code)) return maybe_code;
1174 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 set_target(Code::cast(code));
1176#ifdef DEBUG
1177 TraceIC("KeyedLoadIC", name, state, target());
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001178#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179 return Accessors::FunctionGetPrototype(*object, 0);
1180 }
1181 }
1182
1183 // Check if the name is trivially convertible to an index and get
1184 // the element or char if so.
1185 uint32_t index = 0;
1186 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001187 HandleScope scope(isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 // Rewrite to the generic keyed load stub.
1189 if (FLAG_use_ic) set_target(generic_stub());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001190 return Runtime::GetElementOrCharAt(isolate(), object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001191 }
1192
1193 // Named lookup.
1194 LookupResult lookup;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001195 LookupForRead(*object, *name, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001196
ager@chromium.org5c838252010-02-19 08:53:10 +00001197 // If we did not find a property, check if we need to throw an exception.
1198 if (!lookup.IsProperty()) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001199 if (FLAG_strict || IsContextual(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 return ReferenceError("not_defined", name);
1201 }
1202 }
1203
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001204 if (FLAG_use_ic) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 UpdateCaches(&lookup, state, object, name);
1206 }
1207
1208 PropertyAttributes attr;
ager@chromium.org5c838252010-02-19 08:53:10 +00001209 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001210 // Get the property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001211 Object* result;
1212 { MaybeObject* maybe_result =
1213 object->GetProperty(*object, &lookup, *name, &attr);
1214 if (!maybe_result->ToObject(&result)) return maybe_result;
1215 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001216 // If the property is not present, check if we need to throw an
1217 // exception.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001218 if (attr == ABSENT && IsContextual(object)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219 return ReferenceError("not_defined", name);
1220 }
1221 return result;
1222 }
1223
1224 return object->GetProperty(*object, &lookup, *name, &attr);
1225 }
1226
1227 // Do not use ICs for objects that require access checks (including
1228 // the global object).
1229 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
1230
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001231 if (use_ic) {
ager@chromium.org3811b432009-10-28 14:53:37 +00001232 Code* stub = generic_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001233 if (!force_generic_stub) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001234 if (object->IsString() && key->IsNumber()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001235 if (state == UNINITIALIZED) {
1236 stub = string_stub();
1237 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001238 } else if (object->IsJSObject()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001239 JSObject* receiver = JSObject::cast(*object);
1240 if (receiver->HasIndexedInterceptor()) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001241 stub = indexed_interceptor_stub();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001242 } else if (key->IsSmi()) {
1243 MaybeObject* maybe_stub = ComputeStub(receiver,
1244 false,
1245 kNonStrictMode,
1246 stub);
1247 stub = maybe_stub->IsFailure() ?
1248 NULL : Code::cast(maybe_stub->ToObjectUnchecked());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001249 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001250 }
1251 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001252 if (stub != NULL) set_target(stub);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001253 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001254
1255#ifdef DEBUG
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001256 TraceIC("KeyedLoadIC", key, state, target());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001257#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258
1259 // Get the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001260 return Runtime::GetObjectProperty(isolate(), object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261}
1262
1263
1264void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
1265 Handle<Object> object, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 // Bail out if we didn't find a result.
ager@chromium.org5c838252010-02-19 08:53:10 +00001267 if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268
1269 if (!object->IsJSObject()) return;
1270 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1271
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001272 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001273
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 // Compute the code stub for this load.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001275 MaybeObject* maybe_code = NULL;
1276 Object* code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277
1278 if (state == UNINITIALIZED) {
1279 // This is the first time we execute this inline cache.
1280 // Set the target to the pre monomorphic stub to delay
1281 // setting the monomorphic state.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001282 maybe_code = pre_monomorphic_stub();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 } else {
1284 // Compute a monomorphic stub.
1285 switch (lookup->type()) {
1286 case FIELD: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001287 maybe_code = isolate()->stub_cache()->ComputeKeyedLoadField(
1288 *name, *receiver, lookup->holder(), lookup->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001289 break;
1290 }
1291 case CONSTANT_FUNCTION: {
1292 Object* constant = lookup->GetConstantFunction();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001293 maybe_code = isolate()->stub_cache()->ComputeKeyedLoadConstant(
1294 *name, *receiver, lookup->holder(), constant);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295 break;
1296 }
1297 case CALLBACKS: {
1298 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
1299 AccessorInfo* callback =
1300 AccessorInfo::cast(lookup->GetCallbackObject());
1301 if (v8::ToCData<Address>(callback->getter()) == 0) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 maybe_code = isolate()->stub_cache()->ComputeKeyedLoadCallback(
1303 *name, *receiver, lookup->holder(), callback);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304 break;
1305 }
1306 case INTERCEPTOR: {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001307 ASSERT(HasInterceptorGetter(lookup->holder()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001308 maybe_code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor(
1309 *name, *receiver, lookup->holder());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 break;
1311 }
1312 default: {
1313 // Always rewrite to the generic case so that we do not
1314 // repeatedly try to rewrite.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001315 maybe_code = generic_stub();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 break;
1317 }
1318 }
1319 }
1320
1321 // If we're unable to compute the stub (not enough memory left), we
1322 // simply avoid updating the caches.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001323 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324
1325 // Patch the call site depending on the state of the cache. Make
1326 // sure to always rewrite from monomorphic to megamorphic.
1327 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
1328 if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
1329 set_target(Code::cast(code));
1330 } else if (state == MONOMORPHIC) {
1331 set_target(megamorphic_stub());
1332 }
1333
1334#ifdef DEBUG
1335 TraceIC("KeyedLoadIC", name, state, target());
1336#endif
1337}
1338
1339
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001340static bool StoreICableLookup(LookupResult* lookup) {
1341 // Bail out if we didn't find a result.
ager@chromium.org5c838252010-02-19 08:53:10 +00001342 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return false;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001343
1344 // If the property is read-only, we leave the IC in its current
1345 // state.
1346 if (lookup->IsReadOnly()) return false;
1347
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001348 return true;
1349}
1350
1351
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001352static bool LookupForWrite(JSReceiver* receiver,
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001353 String* name,
1354 LookupResult* lookup) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001355 receiver->LocalLookup(name, lookup);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001356 if (!StoreICableLookup(lookup)) {
1357 return false;
1358 }
1359
1360 if (lookup->type() == INTERCEPTOR) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001361 JSObject* object = JSObject::cast(receiver);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001362 if (object->GetNamedInterceptor()->setter()->IsUndefined()) {
1363 object->LocalLookupRealNamedProperty(name, lookup);
1364 return StoreICableLookup(lookup);
1365 }
1366 }
1367
1368 return true;
1369}
1370
1371
lrn@chromium.org303ada72010-10-27 09:33:13 +00001372MaybeObject* StoreIC::Store(State state,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001373 StrictModeFlag strict_mode,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001374 Handle<Object> object,
1375 Handle<String> name,
1376 Handle<Object> value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001377 // If the object is undefined or null it's illegal to try to set any
1378 // properties on it; throw a TypeError in that case.
1379 if (object->IsUndefined() || object->IsNull()) {
1380 return TypeError("non_object_property_store", object, name);
1381 }
1382
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001383 if (!object->IsJSReceiver()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001384 // The length property of string values is read-only. Throw in strict mode.
1385 if (strict_mode == kStrictMode && object->IsString() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001386 name->Equals(isolate()->heap()->length_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001387 return TypeError("strict_read_only_property", object, name);
1388 }
1389 // Ignore stores where the receiver is not a JSObject.
1390 return *value;
1391 }
1392
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001393 // Handle proxies.
1394 if (object->IsJSProxy()) {
1395 return JSReceiver::cast(*object)->
1396 SetProperty(*name, *value, NONE, strict_mode);
1397 }
1398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1400
1401 // Check if the given name is an array index.
1402 uint32_t index;
1403 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001404 HandleScope scope(isolate());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001405 Handle<Object> result = SetElement(receiver, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001406 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407 return *value;
1408 }
1409
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001410 // Use specialized code for setting the length of arrays.
1411 if (receiver->IsJSArray()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001412 && name->Equals(isolate()->heap()->length_symbol())
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001413 && JSArray::cast(*receiver)->AllowsSetElementsLength()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001414#ifdef DEBUG
1415 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
1416#endif
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001417 Builtins::Name target = (strict_mode == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001418 ? Builtins::kStoreIC_ArrayLength_Strict
1419 : Builtins::kStoreIC_ArrayLength;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001420 set_target(isolate()->builtins()->builtin(target));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001421 return receiver->SetProperty(*name, *value, NONE, strict_mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001422 }
1423
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424 // Lookup the property locally in the receiver.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001425 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
1426 LookupResult lookup;
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00001427
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001428 if (LookupForWrite(*receiver, *name, &lookup)) {
danno@chromium.org160a7b02011-04-18 15:51:38 +00001429 // Generate a stub for this store.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001430 UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001431 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001432 // Strict mode doesn't allow setting non-existent global property
1433 // or an assignment to a read only property.
1434 if (strict_mode == kStrictMode) {
1435 if (lookup.IsFound() && lookup.IsReadOnly()) {
1436 return TypeError("strict_read_only_property", object, name);
1437 } else if (IsContextual(object)) {
1438 return ReferenceError("not_defined", name);
1439 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001440 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001441 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001442 }
1443
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001444 if (receiver->IsJSGlobalProxy()) {
1445 // Generate a generic stub that goes to the runtime when we see a global
1446 // proxy as receiver.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001447 Code* stub = (strict_mode == kStrictMode)
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001448 ? global_proxy_stub_strict()
1449 : global_proxy_stub();
1450 if (target() != stub) {
1451 set_target(stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001452#ifdef DEBUG
1453 TraceIC("StoreIC", name, state, target());
1454#endif
1455 }
1456 }
1457
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458 // Set the property.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001459 return receiver->SetProperty(*name, *value, NONE, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460}
1461
1462
1463void StoreIC::UpdateCaches(LookupResult* lookup,
1464 State state,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001465 StrictModeFlag strict_mode,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 Handle<JSObject> receiver,
1467 Handle<String> name,
1468 Handle<Object> value) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001469 // Skip JSGlobalProxy.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001470 ASSERT(!receiver->IsJSGlobalProxy());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001471
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001472 ASSERT(StoreICableLookup(lookup));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473
1474 // If the property has a non-field type allowing map transitions
1475 // where there is extra room in the object, we leave the IC in its
1476 // current state.
1477 PropertyType type = lookup->type();
1478
1479 // Compute the code stub for this store; used for rewriting to
1480 // monomorphic state and making sure that the code stub is in the
1481 // stub cache.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001482 MaybeObject* maybe_code = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 Object* code = NULL;
1484 switch (type) {
1485 case FIELD: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001486 maybe_code = isolate()->stub_cache()->ComputeStoreField(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001487 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001488 break;
1489 }
1490 case MAP_TRANSITION: {
1491 if (lookup->GetAttributes() != NONE) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001492 HandleScope scope(isolate());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001493 ASSERT(type == MAP_TRANSITION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001494 Handle<Map> transition(lookup->GetTransitionMap());
1495 int index = transition->PropertyIndexFor(*name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001496 maybe_code = isolate()->stub_cache()->ComputeStoreField(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001497 *name, *receiver, index, *transition, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001498 break;
1499 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001500 case NORMAL: {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001501 if (receiver->IsGlobalObject()) {
1502 // The stub generated for the global object picks the value directly
1503 // from the property cell. So the property must be directly on the
1504 // global object.
1505 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
1506 JSGlobalPropertyCell* cell =
1507 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001508 maybe_code = isolate()->stub_cache()->ComputeStoreGlobal(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001509 *name, *global, cell, strict_mode);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001510 } else {
1511 if (lookup->holder() != *receiver) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001512 maybe_code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001513 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001514 break;
1515 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001516 case CALLBACKS: {
1517 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
1518 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
1519 if (v8::ToCData<Address>(callback->setter()) == 0) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001520 maybe_code = isolate()->stub_cache()->ComputeStoreCallback(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001521 *name, *receiver, callback, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001522 break;
1523 }
1524 case INTERCEPTOR: {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001525 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001526 maybe_code = isolate()->stub_cache()->ComputeStoreInterceptor(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001527 *name, *receiver, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528 break;
1529 }
1530 default:
1531 return;
1532 }
1533
1534 // If we're unable to compute the stub (not enough memory left), we
1535 // simply avoid updating the caches.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001536 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001537
1538 // Patch the call site depending on the state of the cache.
1539 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
1540 set_target(Code::cast(code));
1541 } else if (state == MONOMORPHIC) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001542 // Only move to megamorphic if the target changes.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001543 if (target() != Code::cast(code)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001544 set_target((strict_mode == kStrictMode)
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001545 ? megamorphic_stub_strict()
1546 : megamorphic_stub());
1547 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001548 } else if (state == MEGAMORPHIC) {
1549 // Update the stub cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001550 isolate()->stub_cache()->Set(*name,
1551 receiver->map(),
1552 Code::cast(code));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001553 }
1554
1555#ifdef DEBUG
1556 TraceIC("StoreIC", name, state, target());
1557#endif
1558}
1559
1560
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001561static bool AddOneReceiverMapIfMissing(MapList* receiver_maps,
1562 Map* new_receiver_map) {
1563 for (int current = 0; current < receiver_maps->length(); ++current) {
1564 if (receiver_maps->at(current) == new_receiver_map) {
1565 return false;
1566 }
1567 }
1568 receiver_maps->Add(new_receiver_map);
1569 return true;
1570}
1571
1572
1573void KeyedIC::GetReceiverMapsForStub(Code* stub, MapList* result) {
1574 ASSERT(stub->is_inline_cache_stub());
1575 if (stub == string_stub()) {
1576 return result->Add(isolate()->heap()->string_map());
1577 } else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) {
1578 if (stub->ic_state() == MONOMORPHIC) {
1579 result->Add(Map::cast(stub->FindFirstMap()));
1580 } else {
1581 ASSERT(stub->ic_state() == MEGAMORPHIC);
1582 AssertNoAllocation no_allocation;
1583 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
1584 for (RelocIterator it(stub, mask); !it.done(); it.next()) {
1585 RelocInfo* info = it.rinfo();
1586 Object* object = info->target_object();
1587 ASSERT(object->IsMap());
1588 result->Add(Map::cast(object));
1589 }
1590 }
1591 }
1592}
1593
1594
1595MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
1596 bool is_store,
1597 StrictModeFlag strict_mode,
1598 Code* generic_stub) {
1599 State ic_state = target()->ic_state();
1600 Code* monomorphic_stub;
1601 // Always compute the MONOMORPHIC stub, even if the MEGAMORPHIC stub ends up
1602 // being used. This is necessary because the megamorphic stub needs to have
1603 // access to more information than what is stored in the receiver map in some
1604 // cases (external arrays need the array type from the MONOMORPHIC stub).
1605 MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver,
1606 is_store,
1607 strict_mode,
1608 generic_stub);
1609 if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub;
1610
1611 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
1612 return monomorphic_stub;
1613 }
1614 ASSERT(target() != generic_stub);
1615
1616 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
1617 // via megamorphic stubs, since they don't have a map in their relocation info
1618 // and so the stubs can't be harvested for the object needed for a map check.
1619 if (target()->type() != NORMAL) {
1620 return generic_stub;
1621 }
1622
1623 // Determine the list of receiver maps that this call site has seen,
1624 // adding the map that was just encountered.
1625 MapList target_receiver_maps;
1626 GetReceiverMapsForStub(target(), &target_receiver_maps);
1627 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map())) {
1628 // If the miss wasn't due to an unseen map, a MEGAMORPHIC stub
1629 // won't help, use the generic stub.
1630 return generic_stub;
1631 }
1632
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001633 // If the maximum number of receiver maps has been exceeded, use the generic
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001634 // version of the IC.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001635 if (target_receiver_maps.length() > KeyedIC::kMaxKeyedPolymorphism) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001636 return generic_stub;
1637 }
1638
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001639 PolymorphicCodeCache* cache = isolate()->heap()->polymorphic_code_cache();
1640 Code::Flags flags = Code::ComputeFlags(this->kind(),
1641 NOT_IN_LOOP,
1642 MEGAMORPHIC,
1643 strict_mode);
1644 Object* maybe_cached_stub = cache->Lookup(&target_receiver_maps, flags);
1645 // If there is a cached stub, use it.
1646 if (!maybe_cached_stub->IsUndefined()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001647 ASSERT(maybe_cached_stub->IsCode());
1648 return Code::cast(maybe_cached_stub);
1649 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001650 // Collect MONOMORPHIC stubs for all target_receiver_maps.
1651 CodeList handler_ics(target_receiver_maps.length());
1652 for (int i = 0; i < target_receiver_maps.length(); ++i) {
1653 Map* receiver_map(target_receiver_maps.at(i));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001654 MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001655 receiver_map, strict_mode, generic_stub);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001656 Code* cached_stub;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001657 if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001658 handler_ics.Add(cached_stub);
1659 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001660 // Build the MEGAMORPHIC stub.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001661 Code* stub;
1662 maybe_stub = ConstructMegamorphicStub(&target_receiver_maps,
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001663 &handler_ics,
1664 strict_mode);
1665 if (!maybe_stub->To(&stub)) return maybe_stub;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001666 MaybeObject* maybe_update = cache->Update(&target_receiver_maps, flags, stub);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001667 if (maybe_update->IsFailure()) return maybe_update;
1668 return stub;
1669}
1670
1671
1672MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
1673 Map* receiver_map,
1674 StrictModeFlag strict_mode,
1675 Code* generic_stub) {
1676 if ((receiver_map->instance_type() & kNotStringTag) == 0) {
1677 ASSERT(string_stub() != NULL);
1678 return string_stub();
1679 } else if (receiver_map->has_external_array_elements()) {
1680 // Determine the array type from the default MONOMORPHIC already generated
1681 // stub. There is no other way to determine the type of the external array
1682 // directly from the receiver type.
1683 Code::Kind kind = this->kind();
1684 Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
1685 NORMAL,
1686 strict_mode);
1687 String* monomorphic_name = GetStubNameForCache(MONOMORPHIC);
1688 Object* maybe_default_stub = receiver_map->FindInCodeCache(monomorphic_name,
1689 flags);
1690 if (maybe_default_stub->IsUndefined()) {
1691 return generic_stub;
1692 }
1693 Code* default_stub = Code::cast(maybe_default_stub);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001694 Map* first_map = default_stub->FindFirstMap();
1695 return GetExternalArrayStubWithoutMapCheck(first_map->elements_kind());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001696 } else if (receiver_map->has_fast_elements()) {
1697 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1698 return GetFastElementStubWithoutMapCheck(is_js_array);
1699 } else {
1700 return generic_stub;
1701 }
1702}
1703
1704
1705MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver,
1706 bool is_store,
1707 StrictModeFlag strict_mode,
1708 Code* generic_stub) {
1709 Code* result = NULL;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001710 if (receiver->HasFastElements() ||
1711 receiver->HasExternalArrayElements()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001712 MaybeObject* maybe_stub =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001713 isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement(
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001714 receiver, is_store, strict_mode);
1715 if (!maybe_stub->To(&result)) return maybe_stub;
1716 } else {
1717 result = generic_stub;
1718 }
1719 return result;
1720}
1721
1722
1723String* KeyedStoreIC::GetStubNameForCache(IC::State ic_state) {
1724 if (ic_state == MONOMORPHIC) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001725 return isolate()->heap()->KeyedStoreElementMonomorphic_symbol();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001726 } else {
1727 ASSERT(ic_state == MEGAMORPHIC);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001728 return isolate()->heap()->KeyedStoreElementPolymorphic_symbol();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001729 }
1730}
1731
1732
1733MaybeObject* KeyedStoreIC::GetFastElementStubWithoutMapCheck(
1734 bool is_js_array) {
1735 return KeyedStoreFastElementStub(is_js_array).TryGetCode();
1736}
1737
1738
1739MaybeObject* KeyedStoreIC::GetExternalArrayStubWithoutMapCheck(
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001740 JSObject::ElementsKind elements_kind) {
1741 return KeyedStoreExternalArrayStub(elements_kind).TryGetCode();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001742}
1743
1744
1745MaybeObject* KeyedStoreIC::ConstructMegamorphicStub(
1746 MapList* receiver_maps,
1747 CodeList* targets,
1748 StrictModeFlag strict_mode) {
1749 Object* object;
1750 KeyedStoreStubCompiler compiler(strict_mode);
1751 MaybeObject* maybe_code = compiler.CompileStoreMegamorphic(receiver_maps,
1752 targets);
1753 if (!maybe_code->ToObject(&object)) return maybe_code;
1754 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
1755 PROFILE(isolate(), CodeCreateEvent(
1756 Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG,
1757 Code::cast(object), 0));
1758 return object;
1759}
1760
1761
lrn@chromium.org303ada72010-10-27 09:33:13 +00001762MaybeObject* KeyedStoreIC::Store(State state,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001763 StrictModeFlag strict_mode,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001764 Handle<Object> object,
1765 Handle<Object> key,
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001766 Handle<Object> value,
1767 bool force_generic) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001768 if (key->IsSymbol()) {
1769 Handle<String> name = Handle<String>::cast(key);
1770
1771 // If the object is undefined or null it's illegal to try to set any
1772 // properties on it; throw a TypeError in that case.
1773 if (object->IsUndefined() || object->IsNull()) {
1774 return TypeError("non_object_property_store", object, name);
1775 }
1776
1777 // Ignore stores where the receiver is not a JSObject.
1778 if (!object->IsJSObject()) return *value;
1779 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1780
1781 // Check if the given name is an array index.
1782 uint32_t index;
1783 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001784 HandleScope scope(isolate());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001785 Handle<Object> result = SetElement(receiver, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001786 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001787 return *value;
1788 }
1789
1790 // Lookup the property locally in the receiver.
1791 LookupResult lookup;
1792 receiver->LocalLookup(*name, &lookup);
1793
1794 // Update inline cache and stub cache.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001795 if (FLAG_use_ic) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001796 UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797 }
1798
1799 // Set the property.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001800 return receiver->SetProperty(*name, *value, NONE, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001801 }
1802
1803 // Do not use ICs for objects that require access checks (including
1804 // the global object).
1805 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001806 ASSERT(!(use_ic && object->IsJSGlobalProxy()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001807
ager@chromium.org3811b432009-10-28 14:53:37 +00001808 if (use_ic) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001809 Code* stub = (strict_mode == kStrictMode)
1810 ? generic_stub_strict()
1811 : generic_stub();
1812 if (!force_generic) {
1813 if (object->IsJSObject() && key->IsSmi()) {
1814 JSObject* receiver = JSObject::cast(*object);
1815 MaybeObject* maybe_stub = ComputeStub(receiver,
1816 true,
1817 strict_mode,
1818 stub);
1819 stub = maybe_stub->IsFailure() ?
1820 NULL : Code::cast(maybe_stub->ToObjectUnchecked());
ager@chromium.org3811b432009-10-28 14:53:37 +00001821 }
1822 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001823 if (stub != NULL) set_target(stub);
ager@chromium.org3811b432009-10-28 14:53:37 +00001824 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001825
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001826#ifdef DEBUG
1827 TraceIC("KeyedStoreIC", key, state, target());
1828#endif
1829
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001830 // Set the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 return Runtime::SetObjectProperty(
1832 isolate(), object , key, value, NONE, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833}
1834
1835
1836void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
1837 State state,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001838 StrictModeFlag strict_mode,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839 Handle<JSObject> receiver,
1840 Handle<String> name,
1841 Handle<Object> value) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001842 // Skip JSGlobalProxy.
1843 if (receiver->IsJSGlobalProxy()) return;
1844
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001845 // Bail out if we didn't find a result.
ager@chromium.org5c838252010-02-19 08:53:10 +00001846 if (!lookup->IsPropertyOrTransition() || !lookup->IsCacheable()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001847
1848 // If the property is read-only, we leave the IC in its current
1849 // state.
1850 if (lookup->IsReadOnly()) return;
1851
1852 // If the property has a non-field type allowing map transitions
1853 // where there is extra room in the object, we leave the IC in its
1854 // current state.
1855 PropertyType type = lookup->type();
1856
1857 // Compute the code stub for this store; used for rewriting to
1858 // monomorphic state and making sure that the code stub is in the
1859 // stub cache.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001860 MaybeObject* maybe_code = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001861 Object* code = NULL;
1862
1863 switch (type) {
1864 case FIELD: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001865 maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001866 *name, *receiver, lookup->GetFieldIndex(), NULL, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001867 break;
1868 }
1869 case MAP_TRANSITION: {
1870 if (lookup->GetAttributes() == NONE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001871 HandleScope scope(isolate());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001872 ASSERT(type == MAP_TRANSITION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001873 Handle<Map> transition(lookup->GetTransitionMap());
1874 int index = transition->PropertyIndexFor(*name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001875 maybe_code = isolate()->stub_cache()->ComputeKeyedStoreField(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001876 *name, *receiver, index, *transition, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001877 break;
1878 }
1879 // fall through.
1880 }
1881 default: {
1882 // Always rewrite to the generic case so that we do not
1883 // repeatedly try to rewrite.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001884 maybe_code = (strict_mode == kStrictMode)
1885 ? generic_stub_strict()
1886 : generic_stub();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001887 break;
1888 }
1889 }
1890
1891 // If we're unable to compute the stub (not enough memory left), we
1892 // simply avoid updating the caches.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001893 if (maybe_code == NULL || !maybe_code->ToObject(&code)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001894
1895 // Patch the call site depending on the state of the cache. Make
1896 // sure to always rewrite from monomorphic to megamorphic.
1897 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
1898 if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
1899 set_target(Code::cast(code));
1900 } else if (state == MONOMORPHIC) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001901 set_target((strict_mode == kStrictMode)
1902 ? megamorphic_stub_strict()
1903 : megamorphic_stub());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001904 }
1905
1906#ifdef DEBUG
1907 TraceIC("KeyedStoreIC", name, state, target());
1908#endif
1909}
1910
1911
1912// ----------------------------------------------------------------------------
1913// Static IC stub generators.
1914//
1915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001916static JSFunction* CompileFunction(Isolate* isolate,
1917 JSFunction* function,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001918 InLoopFlag in_loop) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001919 // Compile now with optimization.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001920 HandleScope scope(isolate);
1921 Handle<JSFunction> function_handle(function, isolate);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001922 if (in_loop == IN_LOOP) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001923 CompileLazyInLoop(function_handle, CLEAR_EXCEPTION);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001924 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001925 CompileLazy(function_handle, CLEAR_EXCEPTION);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001926 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001927 return *function_handle;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001928}
1929
1930
1931// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001932RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 NoHandleAllocation na;
1934 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001935 CallIC ic(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001936 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001937 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
1938 MaybeObject* maybe_result = ic.LoadFunction(state,
1939 extra_ic_state,
1940 args.at<Object>(0),
1941 args.at<String>(1));
lrn@chromium.org303ada72010-10-27 09:33:13 +00001942 Object* result;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001943 if (!maybe_result->ToObject(&result)) return maybe_result;
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001944
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001945 // The first time the inline cache is updated may be the first time the
1946 // function it references gets called. If the function was lazily compiled
1947 // then the first call will trigger a compilation. We check for this case
1948 // and we do the compilation immediately, instead of waiting for the stub
1949 // currently attached to the JSFunction object to trigger compilation. We
1950 // do this in the case where we know that the inline cache is inside a loop,
1951 // because then we know that we want to optimize the function.
1952 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
1953 return result;
1954 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001955 return CompileFunction(isolate,
1956 JSFunction::cast(result),
1957 ic.target()->ic_in_loop());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958}
1959
1960
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001961// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001962RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001963 NoHandleAllocation na;
1964 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001965 KeyedCallIC ic(isolate);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001966 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001967 Object* result;
1968 { MaybeObject* maybe_result =
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001969 ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1));
lrn@chromium.org303ada72010-10-27 09:33:13 +00001970 if (!maybe_result->ToObject(&result)) return maybe_result;
1971 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001972
1973 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) {
1974 return result;
1975 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001976 return CompileFunction(isolate,
1977 JSFunction::cast(result),
1978 ic.target()->ic_in_loop());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001979}
1980
1981
1982// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001983RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001984 NoHandleAllocation na;
1985 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001986 LoadIC ic(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001987 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001988 return ic.Load(state, args.at<Object>(0), args.at<String>(1));
1989}
1990
1991
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001992// Used from ic-<arch>.cc
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001993RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001994 NoHandleAllocation na;
1995 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001996 KeyedLoadIC ic(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001997 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001998 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), false);
1999}
2000
2001
2002RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) {
2003 NoHandleAllocation na;
2004 ASSERT(args.length() == 2);
2005 KeyedLoadIC ic(isolate);
2006 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
2007 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002008}
2009
2010
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002011// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002012RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 NoHandleAllocation na;
2014 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002015 StoreIC ic(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002016 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002017 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002018 return ic.Store(state,
2019 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
2020 args.at<Object>(0),
2021 args.at<String>(1),
2022 args.at<Object>(2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002023}
2024
2025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002026RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002027 NoHandleAllocation nha;
2028
2029 ASSERT(args.length() == 2);
2030 JSObject* receiver = JSObject::cast(args[0]);
2031 Object* len = args[1];
2032
lrn@chromium.org303ada72010-10-27 09:33:13 +00002033 // The generated code should filter out non-Smis before we get here.
2034 ASSERT(len->IsSmi());
2035
2036 Object* result;
2037 { MaybeObject* maybe_result = receiver->SetElementsLength(len);
2038 if (!maybe_result->ToObject(&result)) return maybe_result;
2039 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002040 return len;
ager@chromium.org5c838252010-02-19 08:53:10 +00002041}
2042
2043
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002044// Extend storage is called in a store inline cache when
2045// it is necessary to extend the properties array of a
2046// JSObject.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002047RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002048 NoHandleAllocation na;
2049 ASSERT(args.length() == 3);
2050
2051 // Convert the parameters
2052 JSObject* object = JSObject::cast(args[0]);
2053 Map* transition = Map::cast(args[1]);
2054 Object* value = args[2];
2055
2056 // Check the object has run out out property space.
2057 ASSERT(object->HasFastProperties());
2058 ASSERT(object->map()->unused_property_fields() == 0);
2059
2060 // Expand the properties array.
2061 FixedArray* old_storage = object->properties();
2062 int new_unused = transition->unused_property_fields();
2063 int new_size = old_storage->length() + new_unused + 1;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002064 Object* result;
2065 { MaybeObject* maybe_result = old_storage->CopySize(new_size);
2066 if (!maybe_result->ToObject(&result)) return maybe_result;
2067 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002068 FixedArray* new_storage = FixedArray::cast(result);
2069 new_storage->set(old_storage->length(), value);
2070
ager@chromium.org32912102009-01-16 10:38:43 +00002071 // Set the new property value and do the map transition.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002072 object->set_properties(new_storage);
2073 object->set_map(transition);
2074
2075 // Return the stored value.
2076 return value;
2077}
2078
2079
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002080// Used from ic-<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002081RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002082 NoHandleAllocation na;
2083 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002084 KeyedStoreIC ic(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002085 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002086 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2087 return ic.Store(state,
2088 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
2089 args.at<Object>(0),
2090 args.at<Object>(1),
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002091 args.at<Object>(2),
2092 false);
2093}
2094
2095
2096RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) {
2097 NoHandleAllocation na;
2098 ASSERT(args.length() == 3);
2099 KeyedStoreIC ic(isolate);
2100 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2101 Handle<Object> object = args.at<Object>(0);
2102 Handle<Object> key = args.at<Object>(1);
2103 Handle<Object> value = args.at<Object>(2);
2104 StrictModeFlag strict_mode =
2105 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode);
2106 return Runtime::SetObjectProperty(isolate,
2107 object,
2108 key,
2109 value,
2110 NONE,
2111 strict_mode);
2112}
2113
2114
2115RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) {
2116 NoHandleAllocation na;
2117 ASSERT(args.length() == 3);
2118 KeyedStoreIC ic(isolate);
2119 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
2120 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
2121 return ic.Store(state,
2122 static_cast<StrictModeFlag>(extra_ic_state & kStrictMode),
2123 args.at<Object>(0),
2124 args.at<Object>(1),
2125 args.at<Object>(2),
2126 true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002127}
2128
2129
danno@chromium.org40cb8782011-05-25 07:58:50 +00002130void UnaryOpIC::patch(Code* code) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002131 set_target(code);
2132}
2133
2134
danno@chromium.org40cb8782011-05-25 07:58:50 +00002135const char* UnaryOpIC::GetName(TypeInfo type_info) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002136 switch (type_info) {
2137 case UNINITIALIZED: return "Uninitialized";
2138 case SMI: return "Smi";
2139 case HEAP_NUMBER: return "HeapNumbers";
2140 case GENERIC: return "Generic";
2141 default: return "Invalid";
2142 }
2143}
2144
2145
danno@chromium.org40cb8782011-05-25 07:58:50 +00002146UnaryOpIC::State UnaryOpIC::ToState(TypeInfo type_info) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002147 switch (type_info) {
2148 case UNINITIALIZED:
2149 return ::v8::internal::UNINITIALIZED;
2150 case SMI:
2151 case HEAP_NUMBER:
2152 return MONOMORPHIC;
2153 case GENERIC:
2154 return MEGAMORPHIC;
2155 }
2156 UNREACHABLE();
2157 return ::v8::internal::UNINITIALIZED;
2158}
2159
danno@chromium.org40cb8782011-05-25 07:58:50 +00002160UnaryOpIC::TypeInfo UnaryOpIC::GetTypeInfo(Handle<Object> operand) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002161 ::v8::internal::TypeInfo operand_type =
2162 ::v8::internal::TypeInfo::TypeFromValue(operand);
2163 if (operand_type.IsSmi()) {
2164 return SMI;
2165 } else if (operand_type.IsNumber()) {
2166 return HEAP_NUMBER;
2167 } else {
2168 return GENERIC;
2169 }
2170}
2171
2172
danno@chromium.org40cb8782011-05-25 07:58:50 +00002173UnaryOpIC::TypeInfo UnaryOpIC::ComputeNewType(
2174 UnaryOpIC::TypeInfo current_type,
2175 UnaryOpIC::TypeInfo previous_type) {
2176 switch (previous_type) {
2177 case UnaryOpIC::UNINITIALIZED:
2178 return current_type;
2179 case UnaryOpIC::SMI:
2180 return (current_type == UnaryOpIC::GENERIC)
2181 ? UnaryOpIC::GENERIC
2182 : UnaryOpIC::HEAP_NUMBER;
2183 case UnaryOpIC::HEAP_NUMBER:
2184 return UnaryOpIC::GENERIC;
2185 case UnaryOpIC::GENERIC:
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002186 // We should never do patching if we are in GENERIC state.
2187 UNREACHABLE();
danno@chromium.org40cb8782011-05-25 07:58:50 +00002188 return UnaryOpIC::GENERIC;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002189 }
2190 UNREACHABLE();
danno@chromium.org40cb8782011-05-25 07:58:50 +00002191 return UnaryOpIC::GENERIC;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002192}
2193
2194
danno@chromium.org40cb8782011-05-25 07:58:50 +00002195void BinaryOpIC::patch(Code* code) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002196 set_target(code);
2197}
2198
2199
danno@chromium.org40cb8782011-05-25 07:58:50 +00002200const char* BinaryOpIC::GetName(TypeInfo type_info) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002201 switch (type_info) {
2202 case UNINITIALIZED: return "Uninitialized";
2203 case SMI: return "SMI";
2204 case INT32: return "Int32s";
2205 case HEAP_NUMBER: return "HeapNumbers";
lrn@chromium.org7516f052011-03-30 08:52:27 +00002206 case ODDBALL: return "Oddball";
danno@chromium.org160a7b02011-04-18 15:51:38 +00002207 case BOTH_STRING: return "BothStrings";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002208 case STRING: return "Strings";
2209 case GENERIC: return "Generic";
2210 default: return "Invalid";
2211 }
2212}
2213
2214
danno@chromium.org40cb8782011-05-25 07:58:50 +00002215BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002216 switch (type_info) {
2217 case UNINITIALIZED:
2218 return ::v8::internal::UNINITIALIZED;
2219 case SMI:
2220 case INT32:
2221 case HEAP_NUMBER:
lrn@chromium.org7516f052011-03-30 08:52:27 +00002222 case ODDBALL:
danno@chromium.org160a7b02011-04-18 15:51:38 +00002223 case BOTH_STRING:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002224 case STRING:
2225 return MONOMORPHIC;
2226 case GENERIC:
2227 return MEGAMORPHIC;
2228 }
2229 UNREACHABLE();
2230 return ::v8::internal::UNINITIALIZED;
2231}
2232
2233
danno@chromium.org40cb8782011-05-25 07:58:50 +00002234BinaryOpIC::TypeInfo BinaryOpIC::JoinTypes(BinaryOpIC::TypeInfo x,
2235 BinaryOpIC::TypeInfo y) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002236 if (x == UNINITIALIZED) return y;
2237 if (y == UNINITIALIZED) return x;
danno@chromium.org160a7b02011-04-18 15:51:38 +00002238 if (x == y) return x;
2239 if (x == BOTH_STRING && y == STRING) return STRING;
2240 if (x == STRING && y == BOTH_STRING) return STRING;
2241 if (x == STRING || x == BOTH_STRING || y == STRING || y == BOTH_STRING) {
2242 return GENERIC;
2243 }
2244 if (x > y) return x;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002245 return y;
2246}
2247
danno@chromium.org160a7b02011-04-18 15:51:38 +00002248
danno@chromium.org40cb8782011-05-25 07:58:50 +00002249BinaryOpIC::TypeInfo BinaryOpIC::GetTypeInfo(Handle<Object> left,
2250 Handle<Object> right) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002251 ::v8::internal::TypeInfo left_type =
2252 ::v8::internal::TypeInfo::TypeFromValue(left);
2253 ::v8::internal::TypeInfo right_type =
2254 ::v8::internal::TypeInfo::TypeFromValue(right);
2255
2256 if (left_type.IsSmi() && right_type.IsSmi()) {
2257 return SMI;
2258 }
2259
2260 if (left_type.IsInteger32() && right_type.IsInteger32()) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002261 // Platforms with 32-bit Smis have no distinct INT32 type.
2262 if (kSmiValueSize == 32) return SMI;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002263 return INT32;
2264 }
2265
2266 if (left_type.IsNumber() && right_type.IsNumber()) {
2267 return HEAP_NUMBER;
2268 }
2269
danno@chromium.org160a7b02011-04-18 15:51:38 +00002270 // Patching for fast string ADD makes sense even if only one of the
2271 // arguments is a string.
2272 if (left_type.IsString()) {
2273 return right_type.IsString() ? BOTH_STRING : STRING;
2274 } else if (right_type.IsString()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002275 return STRING;
2276 }
2277
lrn@chromium.org7516f052011-03-30 08:52:27 +00002278 // Check for oddball objects.
2279 if (left->IsUndefined() && right->IsNumber()) return ODDBALL;
2280 if (left->IsNumber() && right->IsUndefined()) return ODDBALL;
2281
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002282 return GENERIC;
2283}
2284
2285
danno@chromium.org40cb8782011-05-25 07:58:50 +00002286RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002287 ASSERT(args.length() == 4);
2288
2289 HandleScope scope(isolate);
2290 Handle<Object> operand = args.at<Object>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002291 int key = args.smi_at(1);
2292 Token::Value op = static_cast<Token::Value>(args.smi_at(2));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002293 UnaryOpIC::TypeInfo previous_type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002294 static_cast<UnaryOpIC::TypeInfo>(args.smi_at(3));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002295
danno@chromium.org40cb8782011-05-25 07:58:50 +00002296 UnaryOpIC::TypeInfo type = UnaryOpIC::GetTypeInfo(operand);
2297 type = UnaryOpIC::ComputeNewType(type, previous_type);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002298
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002299 UnaryOpStub stub(key, type);
2300 Handle<Code> code = stub.GetCode();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002301 if (!code.is_null()) {
2302 if (FLAG_trace_ic) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002303 PrintF("[UnaryOpIC (%s->%s)#%s]\n",
2304 UnaryOpIC::GetName(previous_type),
2305 UnaryOpIC::GetName(type),
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002306 Token::Name(op));
2307 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002308 UnaryOpIC ic(isolate);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002309 ic.patch(*code);
2310 }
2311
2312 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>(
2313 isolate->thread_local_top()->context_->builtins(), isolate);
2314 Object* builtin = NULL; // Initialization calms down the compiler.
2315 switch (op) {
2316 case Token::SUB:
2317 builtin = builtins->javascript_builtin(Builtins::UNARY_MINUS);
2318 break;
2319 case Token::BIT_NOT:
2320 builtin = builtins->javascript_builtin(Builtins::BIT_NOT);
2321 break;
2322 default:
2323 UNREACHABLE();
2324 }
2325
2326 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate);
2327
2328 bool caught_exception;
2329 Handle<Object> result = Execution::Call(builtin_function, operand, 0, NULL,
2330 &caught_exception);
2331 if (caught_exception) {
2332 return Failure::Exception();
2333 }
2334 return *result;
2335}
2336
danno@chromium.org40cb8782011-05-25 07:58:50 +00002337RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002338 ASSERT(args.length() == 5);
2339
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002340 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002341 Handle<Object> left = args.at<Object>(0);
2342 Handle<Object> right = args.at<Object>(1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002343 int key = args.smi_at(2);
2344 Token::Value op = static_cast<Token::Value>(args.smi_at(3));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002345 BinaryOpIC::TypeInfo previous_type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002346 static_cast<BinaryOpIC::TypeInfo>(args.smi_at(4));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002347
danno@chromium.org40cb8782011-05-25 07:58:50 +00002348 BinaryOpIC::TypeInfo type = BinaryOpIC::GetTypeInfo(left, right);
2349 type = BinaryOpIC::JoinTypes(type, previous_type);
2350 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED;
2351 if ((type == BinaryOpIC::STRING || type == BinaryOpIC::BOTH_STRING) &&
danno@chromium.org160a7b02011-04-18 15:51:38 +00002352 op != Token::ADD) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002353 type = BinaryOpIC::GENERIC;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002354 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002355 if (type == BinaryOpIC::SMI && previous_type == BinaryOpIC::SMI) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002356 if (op == Token::DIV ||
2357 op == Token::MUL ||
2358 op == Token::SHR ||
2359 kSmiValueSize == 32) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002360 // Arithmetic on two Smi inputs has yielded a heap number.
2361 // That is the only way to get here from the Smi stub.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002362 // With 32-bit Smis, all overflows give heap numbers, but with
2363 // 31-bit Smis, most operations overflow to int32 results.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002364 result_type = BinaryOpIC::HEAP_NUMBER;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002365 } else {
2366 // Other operations on SMIs that overflow yield int32s.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002367 result_type = BinaryOpIC::INT32;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002368 }
2369 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002370 if (type == BinaryOpIC::INT32 && previous_type == BinaryOpIC::INT32) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002371 // We must be here because an operation on two INT32 types overflowed.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002372 result_type = BinaryOpIC::HEAP_NUMBER;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002373 }
2374
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002375 BinaryOpStub stub(key, type, result_type);
2376 Handle<Code> code = stub.GetCode();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002377 if (!code.is_null()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002378 if (FLAG_trace_ic) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00002379 PrintF("[BinaryOpIC (%s->(%s->%s))#%s]\n",
2380 BinaryOpIC::GetName(previous_type),
2381 BinaryOpIC::GetName(type),
2382 BinaryOpIC::GetName(result_type),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002383 Token::Name(op));
2384 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002385 BinaryOpIC ic(isolate);
ager@chromium.org378b34e2011-01-28 08:04:38 +00002386 ic.patch(*code);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002387
2388 // Activate inlined smi code.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002389 if (previous_type == BinaryOpIC::UNINITIALIZED) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002390 PatchInlinedSmiCode(ic.address());
2391 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002392 }
2393
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002394 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>(
2395 isolate->thread_local_top()->context_->builtins(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002396 Object* builtin = NULL; // Initialization calms down the compiler.
2397 switch (op) {
2398 case Token::ADD:
2399 builtin = builtins->javascript_builtin(Builtins::ADD);
2400 break;
2401 case Token::SUB:
2402 builtin = builtins->javascript_builtin(Builtins::SUB);
2403 break;
2404 case Token::MUL:
2405 builtin = builtins->javascript_builtin(Builtins::MUL);
2406 break;
2407 case Token::DIV:
2408 builtin = builtins->javascript_builtin(Builtins::DIV);
2409 break;
2410 case Token::MOD:
2411 builtin = builtins->javascript_builtin(Builtins::MOD);
2412 break;
2413 case Token::BIT_AND:
2414 builtin = builtins->javascript_builtin(Builtins::BIT_AND);
2415 break;
2416 case Token::BIT_OR:
2417 builtin = builtins->javascript_builtin(Builtins::BIT_OR);
2418 break;
2419 case Token::BIT_XOR:
2420 builtin = builtins->javascript_builtin(Builtins::BIT_XOR);
2421 break;
2422 case Token::SHR:
2423 builtin = builtins->javascript_builtin(Builtins::SHR);
2424 break;
2425 case Token::SAR:
2426 builtin = builtins->javascript_builtin(Builtins::SAR);
2427 break;
2428 case Token::SHL:
2429 builtin = builtins->javascript_builtin(Builtins::SHL);
2430 break;
2431 default:
2432 UNREACHABLE();
2433 }
2434
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002435 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002436
2437 bool caught_exception;
2438 Object** builtin_args[] = { right.location() };
2439 Handle<Object> result = Execution::Call(builtin_function,
2440 left,
2441 ARRAY_SIZE(builtin_args),
2442 builtin_args,
2443 &caught_exception);
2444 if (caught_exception) {
2445 return Failure::Exception();
2446 }
2447 return *result;
2448}
2449
2450
2451Handle<Code> CompareIC::GetUninitialized(Token::Value op) {
2452 ICCompareStub stub(op, UNINITIALIZED);
2453 return stub.GetCode();
2454}
2455
2456
2457CompareIC::State CompareIC::ComputeState(Code* target) {
2458 int key = target->major_key();
2459 if (key == CodeStub::Compare) return GENERIC;
2460 ASSERT(key == CodeStub::CompareIC);
2461 return static_cast<State>(target->compare_state());
2462}
2463
2464
2465const char* CompareIC::GetStateName(State state) {
2466 switch (state) {
2467 case UNINITIALIZED: return "UNINITIALIZED";
2468 case SMIS: return "SMIS";
2469 case HEAP_NUMBERS: return "HEAP_NUMBERS";
2470 case OBJECTS: return "OBJECTS";
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002471 case SYMBOLS: return "SYMBOLS";
lrn@chromium.org1c092762011-05-09 09:42:16 +00002472 case STRINGS: return "STRINGS";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002473 case GENERIC: return "GENERIC";
2474 default:
2475 UNREACHABLE();
2476 return NULL;
2477 }
2478}
2479
2480
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002481CompareIC::State CompareIC::TargetState(State state,
2482 bool has_inlined_smi_code,
2483 Handle<Object> x,
2484 Handle<Object> y) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002485 if (!has_inlined_smi_code && state != UNINITIALIZED && state != SYMBOLS) {
2486 return GENERIC;
2487 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002488 if (state == UNINITIALIZED && x->IsSmi() && y->IsSmi()) return SMIS;
2489 if ((state == UNINITIALIZED || (state == SMIS && has_inlined_smi_code)) &&
2490 x->IsNumber() && y->IsNumber()) return HEAP_NUMBERS;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002491 if (op_ != Token::EQ && op_ != Token::EQ_STRICT) return GENERIC;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002492 if (state == UNINITIALIZED &&
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002493 x->IsSymbol() && y->IsSymbol()) return SYMBOLS;
2494 if ((state == UNINITIALIZED || state == SYMBOLS) &&
lrn@chromium.org1c092762011-05-09 09:42:16 +00002495 x->IsString() && y->IsString()) return STRINGS;
2496 if (state == UNINITIALIZED &&
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002497 x->IsJSObject() && y->IsJSObject()) return OBJECTS;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002498 return GENERIC;
2499}
2500
2501
2502// Used from ic_<arch>.cc.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002503RUNTIME_FUNCTION(Code*, CompareIC_Miss) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002504 NoHandleAllocation na;
2505 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002506 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002507 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
2508 return ic.target();
2509}
2510
2511
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512static const Address IC_utilities[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002513#define ADDR(name) FUNCTION_ADDR(name),
2514 IC_UTIL_LIST(ADDR)
2515 NULL
2516#undef ADDR
2517};
2518
2519
2520Address IC::AddressFromUtilityId(IC::UtilityId id) {
2521 return IC_utilities[id];
2522}
2523
2524
2525} } // namespace v8::internal