blob: ccdf3cab43cb7f350de0a5dc939581e8eadfafd7 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 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"
33#include "execution.h"
34#include "ic-inl.h"
35#include "runtime.h"
36#include "stub-cache.h"
37
38namespace v8 { namespace internal {
39
40#ifdef DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041static char TransitionMarkFromState(IC::State state) {
42 switch (state) {
43 case UNINITIALIZED: return '0';
ager@chromium.org3bf7b912008-11-17 09:09:45 +000044 case UNINITIALIZED_IN_LOOP: return 'L';
ager@chromium.org5ec48922009-05-05 07:25:34 +000045 case PREMONOMORPHIC: return 'P';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046 case MONOMORPHIC: return '1';
47 case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
48 case MEGAMORPHIC: return 'N';
49
50 // We never see the debugger states here, because the state is
51 // computed from the original code - not the patched code. Let
52 // these cases fall through to the unreachable code below.
53 case DEBUG_BREAK: break;
54 case DEBUG_PREPARE_STEP_IN: break;
55 }
56 UNREACHABLE();
57 return 0;
58}
59
60void IC::TraceIC(const char* type,
61 Handle<String> name,
62 State old_state,
63 Code* new_target) {
64 if (FLAG_trace_ic) {
65 State new_state = StateFrom(new_target, Heap::undefined_value());
66 PrintF("[%s (%c->%c) ", type,
67 TransitionMarkFromState(old_state),
68 TransitionMarkFromState(new_state));
69 name->Print();
70 PrintF("]\n");
71 }
72}
73#endif
74
75
76IC::IC(FrameDepth depth) {
77 // To improve the performance of the (much used) IC code, we unfold
78 // a few levels of the stack frame iteration code. This yields a
79 // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag.
80 const Address entry = Top::c_entry_fp(Top::GetCurrentThread());
81 Address* pc_address =
82 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
83 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
84 // If there's another JavaScript frame on the stack, we need to look
85 // one frame further down the stack to find the frame pointer and
86 // the return address stack slot.
87 if (depth == EXTRA_CALL_FRAME) {
88 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
89 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
90 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
91 }
92#ifdef DEBUG
93 StackFrameIterator it;
94 for (int i = 0; i < depth + 1; i++) it.Advance();
95 StackFrame* frame = it.frame();
96 ASSERT(fp == frame->fp() && pc_address == frame->pc_address());
97#endif
98 fp_ = fp;
99 pc_address_ = pc_address;
100}
101
102
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000103#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104Address IC::OriginalCodeAddress() {
105 HandleScope scope;
106 // Compute the JavaScript frame for the frame pointer of this IC
107 // structure. We need this to be able to find the function
108 // corresponding to the frame.
109 StackFrameIterator it;
110 while (it.frame()->fp() != this->fp()) it.Advance();
111 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
112 // Find the function on the stack and both the active code for the
113 // function and the original code.
114 JSFunction* function = JSFunction::cast(frame->function());
115 Handle<SharedFunctionInfo> shared(function->shared());
116 Code* code = shared->code();
117 ASSERT(Debug::HasDebugInfo(shared));
118 Code* original_code = Debug::GetDebugInfo(shared)->original_code();
119 ASSERT(original_code->IsCode());
120 // Get the address of the call site in the active code. This is the
121 // place where the call to DebugBreakXXX is and where the IC
122 // normally would be.
123 Address addr = pc() - Assembler::kTargetAddrToReturnAddrDist;
124 // Return the address in the original code. This is the place where
ager@chromium.org32912102009-01-16 10:38:43 +0000125 // the call which has been overwritten by the DebugBreakXXX resides
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000126 // and the place where the inline cache system should look.
127 int delta = original_code->instruction_start() - code->instruction_start();
128 return addr + delta;
129}
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000130#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000131
132IC::State IC::StateFrom(Code* target, Object* receiver) {
kasper.lund7276f142008-07-30 08:49:36 +0000133 IC::State state = target->ic_state();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134
135 if (state != MONOMORPHIC) return state;
136 if (receiver->IsUndefined() || receiver->IsNull()) return state;
137
138 Map* map = GetCodeCacheMapForObject(receiver);
139
140 // Decide whether the inline cache failed because of changes to the
141 // receiver itself or changes to one of its prototypes.
142 //
143 // If there are changes to the receiver itself, the map of the
144 // receiver will have changed and the current target will not be in
145 // the receiver map's code cache. Therefore, if the current target
146 // is in the receiver map's code cache, the inline cache failed due
147 // to prototype check failure.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000148 int index = map->IndexInCodeCache(target);
149 if (index >= 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000150 // For keyed load/store, the most likely cause of cache failure is
151 // that the key has changed. We do not distinguish between
152 // prototype and non-prototype failures for keyed access.
153 Code::Kind kind = target->kind();
154 if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) {
155 return MONOMORPHIC;
156 }
157
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000158 // Remove the target from the code cache to avoid hitting the same
159 // invalid stub again.
160 map->RemoveFromCodeCache(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000161
162 return MONOMORPHIC_PROTOTYPE_FAILURE;
163 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000164
165 // The builtins object is special. It only changes when JavaScript
166 // builtins are loaded lazily. It is important to keep inline
167 // caches for the builtins object monomorphic. Therefore, if we get
168 // an inline cache miss for the builtins object after lazily loading
ager@chromium.org236ad962008-09-25 09:45:57 +0000169 // JavaScript builtins, we return uninitialized as the state to
170 // force the inline cache back to monomorphic state.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000171 if (receiver->IsJSBuiltinsObject()) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000172 return UNINITIALIZED;
173 }
174
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000175 return MONOMORPHIC;
176}
177
178
ager@chromium.org236ad962008-09-25 09:45:57 +0000179RelocInfo::Mode IC::ComputeMode() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000180 Address addr = address();
181 Code* code = Code::cast(Heap::FindCodeObject(addr));
182 for (RelocIterator it(code, RelocInfo::kCodeTargetMask);
183 !it.done(); it.next()) {
184 RelocInfo* info = it.rinfo();
185 if (info->pc() == addr) return info->rmode();
186 }
187 UNREACHABLE();
ager@chromium.org236ad962008-09-25 09:45:57 +0000188 return RelocInfo::NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000189}
190
191
192Failure* IC::TypeError(const char* type,
193 Handle<Object> object,
194 Handle<String> name) {
195 HandleScope scope;
196 Handle<Object> args[2] = { name, object };
197 Handle<Object> error = Factory::NewTypeError(type, HandleVector(args, 2));
198 return Top::Throw(*error);
199}
200
201
202Failure* IC::ReferenceError(const char* type, Handle<String> name) {
203 HandleScope scope;
204 Handle<Object> error =
205 Factory::NewReferenceError(type, HandleVector(&name, 1));
206 return Top::Throw(*error);
207}
208
209
210void IC::Clear(Address address) {
211 Code* target = GetTargetAtAddress(address);
212
213 // Don't clear debug break inline cache as it will remove the break point.
kasper.lund7276f142008-07-30 08:49:36 +0000214 if (target->ic_state() == DEBUG_BREAK) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000215
216 switch (target->kind()) {
217 case Code::LOAD_IC: return LoadIC::Clear(address, target);
218 case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target);
219 case Code::STORE_IC: return StoreIC::Clear(address, target);
220 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target);
221 case Code::CALL_IC: return CallIC::Clear(address, target);
222 default: UNREACHABLE();
223 }
224}
225
226
227void CallIC::Clear(Address address, Code* target) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000228 State state = target->ic_state();
229 if (state == UNINITIALIZED || state == UNINITIALIZED_IN_LOOP) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230 Code* code = StubCache::FindCallInitialize(target->arguments_count());
231 SetTargetAtAddress(address, code);
232}
233
234
235void KeyedLoadIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000236 if (target->ic_state() == UNINITIALIZED) return;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000237 // Make sure to also clear the map used in inline fast cases. If we
238 // do not clear these maps, cached code can keep objects alive
239 // through the embedded maps.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000240 ClearInlinedVersion(address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000241 SetTargetAtAddress(address, initialize_stub());
242}
243
244
245void LoadIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000246 if (target->ic_state() == UNINITIALIZED) return;
ager@chromium.org5ec48922009-05-05 07:25:34 +0000247 ClearInlinedVersion(address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000248 SetTargetAtAddress(address, initialize_stub());
249}
250
251
252void StoreIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000253 if (target->ic_state() == UNINITIALIZED) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000254 SetTargetAtAddress(address, initialize_stub());
255}
256
257
258void KeyedStoreIC::Clear(Address address, Code* target) {
kasper.lund7276f142008-07-30 08:49:36 +0000259 if (target->ic_state() == UNINITIALIZED) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000260 SetTargetAtAddress(address, initialize_stub());
261}
262
263
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000264Object* CallIC::TryCallAsFunction(Object* object) {
265 HandleScope scope;
266 Handle<Object> target(object);
267 Handle<Object> delegate = Execution::GetFunctionDelegate(target);
268
269 if (delegate->IsJSFunction()) {
270 // Patch the receiver and use the delegate as the function to
271 // invoke. This is used for invoking objects as if they were
272 // functions.
273 const int argc = this->target()->arguments_count();
274 StackFrameLocator locator;
275 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
276 int index = frame->ComputeExpressionsCount() - (argc + 1);
277 frame->SetExpression(index, *target);
278 }
279
280 return *delegate;
281}
282
283
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000284Object* CallIC::LoadFunction(State state,
285 Handle<Object> object,
286 Handle<String> name) {
287 // If the object is undefined or null it's illegal to try to get any
288 // of its properties; throw a TypeError in that case.
289 if (object->IsUndefined() || object->IsNull()) {
290 return TypeError("non_object_property_call", object, name);
291 }
292
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000293 Object* result = Heap::the_hole_value();
294
295 // Check if the name is trivially convertible to an index and get
296 // the element if so.
297 uint32_t index;
298 if (name->AsArrayIndex(&index)) {
299 result = object->GetElement(index);
300 if (result->IsJSFunction()) return result;
301
302 // Try to find a suitable function delegate for the object at hand.
303 result = TryCallAsFunction(result);
304 if (result->IsJSFunction()) return result;
305
306 // Otherwise, it will fail in the lookup step.
307 }
308
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309 // Lookup the property in the object.
310 LookupResult lookup;
311 object->Lookup(*name, &lookup);
312
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313 if (!lookup.IsValid()) {
314 // If the object does not have the requested property, check which
315 // exception we need to throw.
316 if (is_contextual()) {
317 return ReferenceError("not_defined", name);
318 }
319 return TypeError("undefined_method", object, name);
320 }
321
322 // Lookup is valid: Update inline cache and stub cache.
323 if (FLAG_use_ic && lookup.IsLoaded()) {
324 UpdateCaches(&lookup, state, object, name);
325 }
326
327 if (lookup.type() == INTERCEPTOR) {
328 // Get the property.
329 PropertyAttributes attr;
330 result = object->GetProperty(*name, &attr);
331 if (result->IsFailure()) return result;
332 // If the object does not have the requested property, check which
333 // exception we need to throw.
334 if (attr == ABSENT) {
335 if (is_contextual()) {
336 return ReferenceError("not_defined", name);
337 }
338 return TypeError("undefined_method", object, name);
339 }
340 } else {
341 // Lookup is valid and no interceptors are involved. Get the
342 // property.
343 result = object->GetProperty(*name);
344 if (result->IsFailure()) return result;
345 }
346
347 ASSERT(result != Heap::the_hole_value());
348
349 if (result->IsJSFunction()) {
350 // Check if there is an optimized (builtin) version of the function.
351 // Ignored this will degrade performance for Array.prototype.{push,pop}.
352 // Please note we only return the optimized function iff
353 // the JSObject has FastElements.
354 if (object->IsJSObject() && JSObject::cast(*object)->HasFastElements()) {
355 Object* opt = Top::LookupSpecialFunction(JSObject::cast(*object),
356 lookup.holder(),
357 JSFunction::cast(result));
358 if (opt->IsJSFunction()) return opt;
359 }
360
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000361#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000362 // Handle stepping into a function if step into is active.
363 if (Debug::StepInActive()) {
364 // Protect the result in a handle as the debugger can allocate and might
365 // cause GC.
366 HandleScope scope;
367 Handle<JSFunction> function(JSFunction::cast(result));
368 Debug::HandleStepIn(function, fp(), false);
369 return *function;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000370 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000371#endif
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000372
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000373 return result;
374 }
375
376 // Try to find a suitable function delegate for the object at hand.
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000377 result = TryCallAsFunction(result);
378 return result->IsJSFunction() ?
379 result : TypeError("property_not_function", object, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000380}
381
382
383void CallIC::UpdateCaches(LookupResult* lookup,
384 State state,
385 Handle<Object> object,
386 Handle<String> name) {
387 ASSERT(lookup->IsLoaded());
388 // Bail out if we didn't find a result.
389 if (!lookup->IsValid() || !lookup->IsCacheable()) return;
390
391 // Compute the number of arguments.
392 int argc = target()->arguments_count();
393 Object* code = NULL;
394
395 if (state == UNINITIALIZED) {
396 // This is the first time we execute this inline cache.
397 // Set the target to the pre monomorphic stub to delay
398 // setting the monomorphic state.
399 code = StubCache::ComputeCallPreMonomorphic(argc);
400 } else if (state == MONOMORPHIC) {
401 code = StubCache::ComputeCallMegamorphic(argc);
402 } else {
403 // Compute monomorphic stub.
404 switch (lookup->type()) {
405 case FIELD: {
406 int index = lookup->GetFieldIndex();
407 code = StubCache::ComputeCallField(argc, *name, *object,
408 lookup->holder(), index);
409 break;
410 }
411 case CONSTANT_FUNCTION: {
412 // Get the constant function and compute the code stub for this
413 // call; used for rewriting to monomorphic state and making sure
414 // that the code stub is in the stub cache.
415 JSFunction* function = lookup->GetConstantFunction();
416 code = StubCache::ComputeCallConstant(argc, *name, *object,
417 lookup->holder(), function);
418 break;
419 }
420 case NORMAL: {
421 // There is only one shared stub for calling normalized
422 // properties. It does not traverse the prototype chain, so the
423 // property must be found in the receiver for the stub to be
424 // applicable.
425 if (!object->IsJSObject()) return;
426 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
427 if (lookup->holder() != *receiver) return;
428 code = StubCache::ComputeCallNormal(argc, *name, *receiver);
429 break;
430 }
431 case INTERCEPTOR: {
432 code = StubCache::ComputeCallInterceptor(argc, *name, *object,
433 lookup->holder());
434 break;
435 }
436 default:
437 return;
438 }
439 }
440
441 // If we're unable to compute the stub (not enough memory left), we
442 // simply avoid updating the caches.
443 if (code->IsFailure()) return;
444
445 // Patch the call site depending on the state of the cache.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000446 if (state == UNINITIALIZED || state == UNINITIALIZED_IN_LOOP ||
447 state == PREMONOMORPHIC || state == MONOMORPHIC ||
448 state == MONOMORPHIC_PROTOTYPE_FAILURE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449 set_target(Code::cast(code));
450 }
451
452#ifdef DEBUG
453 TraceIC("CallIC", name, state, target());
454#endif
455}
456
457
458Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
459 // If the object is undefined or null it's illegal to try to get any
460 // of its properties; throw a TypeError in that case.
461 if (object->IsUndefined() || object->IsNull()) {
462 return TypeError("non_object_property_load", object, name);
463 }
464
465 if (FLAG_use_ic) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000466 // Use specialized code for getting the length of strings and
467 // string wrapper objects. The length property of string wrapper
468 // objects is read-only and therefore always returns the length of
469 // the underlying string value. See ECMA-262 15.5.5.1.
470 if ((object->IsString() || object->IsStringWrapper()) &&
471 name->Equals(Heap::length_symbol())) {
472 HandleScope scope;
473 // Get the string if we have a string wrapper object.
474 if (object->IsJSValue()) {
475 object = Handle<Object>(Handle<JSValue>::cast(object)->value());
476 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000477#ifdef DEBUG
478 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
479#endif
480 Code* target = NULL;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000481 target = Builtins::builtin(Builtins::LoadIC_StringLength);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000482 set_target(target);
483 StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
484 return Smi::FromInt(String::cast(*object)->length());
485 }
486
487 // Use specialized code for getting the length of arrays.
488 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) {
489#ifdef DEBUG
490 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
491#endif
492 Code* target = Builtins::builtin(Builtins::LoadIC_ArrayLength);
493 set_target(target);
494 StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
495 return JSArray::cast(*object)->length();
496 }
497
498 // Use specialized code for getting prototype of functions.
499 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) {
500#ifdef DEBUG
501 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
502#endif
503 Code* target = Builtins::builtin(Builtins::LoadIC_FunctionPrototype);
504 set_target(target);
505 StubCache::Set(*name, HeapObject::cast(*object)->map(), target);
506 return Accessors::FunctionGetPrototype(*object, 0);
507 }
508 }
509
510 // Check if the name is trivially convertible to an index and get
511 // the element if so.
512 uint32_t index;
513 if (name->AsArrayIndex(&index)) return object->GetElement(index);
514
515 // Named lookup in the object.
516 LookupResult lookup;
517 object->Lookup(*name, &lookup);
518
519 // If lookup is invalid, check if we need to throw an exception.
520 if (!lookup.IsValid()) {
521 if (FLAG_strict || is_contextual()) {
522 return ReferenceError("not_defined", name);
523 }
ager@chromium.org8bb60582008-12-11 12:02:20 +0000524 LOG(SuspectReadEvent(*name, *object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000525 }
526
ager@chromium.org5ec48922009-05-05 07:25:34 +0000527 bool can_be_inlined =
528 FLAG_use_ic &&
529 state == PREMONOMORPHIC &&
530 lookup.IsValid() &&
531 lookup.IsLoaded() &&
532 lookup.IsCacheable() &&
533 lookup.holder() == *object &&
534 lookup.type() == FIELD &&
535 !object->IsAccessCheckNeeded();
536
537 if (can_be_inlined) {
538 Map* map = lookup.holder()->map();
539 // Property's index in the properties array. If negative we have
540 // an inobject property.
541 int index = lookup.GetFieldIndex() - map->inobject_properties();
542 if (index < 0) {
543 // Index is an offset from the end of the object.
544 int offset = map->instance_size() + (index * kPointerSize);
545 if (PatchInlinedLoad(address(), map, offset)) {
546 set_target(megamorphic_stub());
547 return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex());
548 }
549 }
550 }
551
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000552 // Update inline cache and stub cache.
553 if (FLAG_use_ic && lookup.IsLoaded()) {
554 UpdateCaches(&lookup, state, object, name);
555 }
556
557 PropertyAttributes attr;
558 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) {
559 // Get the property.
560 Object* result = object->GetProperty(*object, &lookup, *name, &attr);
561 if (result->IsFailure()) return result;
562 // If the property is not present, check if we need to throw an
563 // exception.
564 if (attr == ABSENT && is_contextual()) {
565 return ReferenceError("not_defined", name);
566 }
567 return result;
568 }
569
570 // Get the property.
571 return object->GetProperty(*object, &lookup, *name, &attr);
572}
573
574
575void LoadIC::UpdateCaches(LookupResult* lookup,
576 State state,
577 Handle<Object> object,
578 Handle<String> name) {
579 ASSERT(lookup->IsLoaded());
580 // Bail out if we didn't find a result.
581 if (!lookup->IsValid() || !lookup->IsCacheable()) return;
582
583 // Loading properties from values is not common, so don't try to
584 // deal with non-JS objects here.
585 if (!object->IsJSObject()) return;
586 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
587
588 // Compute the code stub for this load.
589 Object* code = NULL;
590 if (state == UNINITIALIZED) {
591 // This is the first time we execute this inline cache.
592 // Set the target to the pre monomorphic stub to delay
593 // setting the monomorphic state.
594 code = pre_monomorphic_stub();
595 } else {
596 // Compute monomorphic stub.
597 switch (lookup->type()) {
598 case FIELD: {
599 code = StubCache::ComputeLoadField(*name, *receiver,
600 lookup->holder(),
601 lookup->GetFieldIndex());
602 break;
603 }
604 case CONSTANT_FUNCTION: {
605 Object* constant = lookup->GetConstantFunction();
606 code = StubCache::ComputeLoadConstant(*name, *receiver,
607 lookup->holder(), constant);
608 break;
609 }
610 case NORMAL: {
611 // There is only one shared stub for loading normalized
612 // properties. It does not traverse the prototype chain, so the
613 // property must be found in the receiver for the stub to be
614 // applicable.
615 if (lookup->holder() != *receiver) return;
616 code = StubCache::ComputeLoadNormal(*name, *receiver);
617 break;
618 }
619 case CALLBACKS: {
620 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
621 AccessorInfo* callback =
622 AccessorInfo::cast(lookup->GetCallbackObject());
623 if (v8::ToCData<Address>(callback->getter()) == 0) return;
624 code = StubCache::ComputeLoadCallback(*name, *receiver,
625 lookup->holder(), callback);
626 break;
627 }
628 case INTERCEPTOR: {
629 code = StubCache::ComputeLoadInterceptor(*name, *receiver,
630 lookup->holder());
631 break;
632 }
633 default:
634 return;
635 }
636 }
637
638 // If we're unable to compute the stub (not enough memory left), we
639 // simply avoid updating the caches.
640 if (code->IsFailure()) return;
641
642 // Patch the call site depending on the state of the cache.
643 if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
644 state == MONOMORPHIC_PROTOTYPE_FAILURE) {
645 set_target(Code::cast(code));
646 } else if (state == MONOMORPHIC) {
647 set_target(megamorphic_stub());
648 }
649
650#ifdef DEBUG
651 TraceIC("LoadIC", name, state, target());
652#endif
653}
654
655
656Object* KeyedLoadIC::Load(State state,
657 Handle<Object> object,
658 Handle<Object> key) {
659 if (key->IsSymbol()) {
660 Handle<String> name = Handle<String>::cast(key);
661
662 // If the object is undefined or null it's illegal to try to get any
663 // of its properties; throw a TypeError in that case.
664 if (object->IsUndefined() || object->IsNull()) {
665 return TypeError("non_object_property_load", object, name);
666 }
667
668 if (FLAG_use_ic) {
669 // Use specialized code for getting the length of strings.
670 if (object->IsString() && name->Equals(Heap::length_symbol())) {
671 Handle<String> string = Handle<String>::cast(object);
672 Object* code = NULL;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000673 code = StubCache::ComputeKeyedLoadStringLength(*name, *string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674 if (code->IsFailure()) return code;
675 set_target(Code::cast(code));
676#ifdef DEBUG
677 TraceIC("KeyedLoadIC", name, state, target());
678#endif
679 return Smi::FromInt(string->length());
680 }
681
682 // Use specialized code for getting the length of arrays.
683 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) {
684 Handle<JSArray> array = Handle<JSArray>::cast(object);
685 Object* code = StubCache::ComputeKeyedLoadArrayLength(*name, *array);
686 if (code->IsFailure()) return code;
687 set_target(Code::cast(code));
688#ifdef DEBUG
689 TraceIC("KeyedLoadIC", name, state, target());
690#endif
691 return JSArray::cast(*object)->length();
692 }
693
694 // Use specialized code for getting prototype of functions.
695 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) {
696 Handle<JSFunction> function = Handle<JSFunction>::cast(object);
697 Object* code =
698 StubCache::ComputeKeyedLoadFunctionPrototype(*name, *function);
699 if (code->IsFailure()) return code;
700 set_target(Code::cast(code));
701#ifdef DEBUG
702 TraceIC("KeyedLoadIC", name, state, target());
703#endif
704 return Accessors::FunctionGetPrototype(*object, 0);
705 }
706 }
707
708 // Check if the name is trivially convertible to an index and get
709 // the element or char if so.
710 uint32_t index = 0;
711 if (name->AsArrayIndex(&index)) {
712 HandleScope scope;
713 // Rewrite to the generic keyed load stub.
714 if (FLAG_use_ic) set_target(generic_stub());
715 return Runtime::GetElementOrCharAt(object, index);
716 }
717
718 // Named lookup.
719 LookupResult lookup;
720 object->Lookup(*name, &lookup);
721
722 // If lookup is invalid, check if we need to throw an exception.
723 if (!lookup.IsValid()) {
724 if (FLAG_strict || is_contextual()) {
725 return ReferenceError("not_defined", name);
726 }
727 }
728
729 // Update the inline cache.
730 if (FLAG_use_ic && lookup.IsLoaded()) {
731 UpdateCaches(&lookup, state, object, name);
732 }
733
734 PropertyAttributes attr;
735 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) {
736 // Get the property.
737 Object* result = object->GetProperty(*object, &lookup, *name, &attr);
738 if (result->IsFailure()) return result;
739 // If the property is not present, check if we need to throw an
740 // exception.
741 if (attr == ABSENT && is_contextual()) {
742 return ReferenceError("not_defined", name);
743 }
744 return result;
745 }
746
747 return object->GetProperty(*object, &lookup, *name, &attr);
748 }
749
750 // Do not use ICs for objects that require access checks (including
751 // the global object).
752 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
753
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000754 if (use_ic) {
755 set_target(generic_stub());
756 // For JSObjects that are not value wrappers and that do not have
757 // indexed interceptors, we initialize the inlined fast case (if
758 // present) by patching the inlined map check.
759 if (object->IsJSObject() &&
760 !object->IsJSValue() &&
761 !JSObject::cast(*object)->HasIndexedInterceptor()) {
762 Map* map = JSObject::cast(*object)->map();
ager@chromium.org5ec48922009-05-05 07:25:34 +0000763 PatchInlinedLoad(address(), map);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000764 }
765 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000766
767 // Get the property.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000768 return Runtime::GetObjectProperty(object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769}
770
771
772void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
773 Handle<Object> object, Handle<String> name) {
774 ASSERT(lookup->IsLoaded());
775 // Bail out if we didn't find a result.
776 if (!lookup->IsValid() || !lookup->IsCacheable()) return;
777
778 if (!object->IsJSObject()) return;
779 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
780
781 // Compute the code stub for this load.
782 Object* code = NULL;
783
784 if (state == UNINITIALIZED) {
785 // This is the first time we execute this inline cache.
786 // Set the target to the pre monomorphic stub to delay
787 // setting the monomorphic state.
788 code = pre_monomorphic_stub();
789 } else {
790 // Compute a monomorphic stub.
791 switch (lookup->type()) {
792 case FIELD: {
793 code = StubCache::ComputeKeyedLoadField(*name, *receiver,
794 lookup->holder(),
795 lookup->GetFieldIndex());
796 break;
797 }
798 case CONSTANT_FUNCTION: {
799 Object* constant = lookup->GetConstantFunction();
800 code = StubCache::ComputeKeyedLoadConstant(*name, *receiver,
801 lookup->holder(), constant);
802 break;
803 }
804 case CALLBACKS: {
805 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
806 AccessorInfo* callback =
807 AccessorInfo::cast(lookup->GetCallbackObject());
808 if (v8::ToCData<Address>(callback->getter()) == 0) return;
809 code = StubCache::ComputeKeyedLoadCallback(*name, *receiver,
810 lookup->holder(), callback);
811 break;
812 }
813 case INTERCEPTOR: {
814 code = StubCache::ComputeKeyedLoadInterceptor(*name, *receiver,
815 lookup->holder());
816 break;
817 }
818 default: {
819 // Always rewrite to the generic case so that we do not
820 // repeatedly try to rewrite.
821 code = generic_stub();
822 break;
823 }
824 }
825 }
826
827 // If we're unable to compute the stub (not enough memory left), we
828 // simply avoid updating the caches.
829 if (code->IsFailure()) return;
830
831 // Patch the call site depending on the state of the cache. Make
832 // sure to always rewrite from monomorphic to megamorphic.
833 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
834 if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
835 set_target(Code::cast(code));
836 } else if (state == MONOMORPHIC) {
837 set_target(megamorphic_stub());
838 }
839
840#ifdef DEBUG
841 TraceIC("KeyedLoadIC", name, state, target());
842#endif
843}
844
845
846Object* StoreIC::Store(State state,
847 Handle<Object> object,
848 Handle<String> name,
849 Handle<Object> value) {
850 // If the object is undefined or null it's illegal to try to set any
851 // properties on it; throw a TypeError in that case.
852 if (object->IsUndefined() || object->IsNull()) {
853 return TypeError("non_object_property_store", object, name);
854 }
855
856 // Ignore stores where the receiver is not a JSObject.
857 if (!object->IsJSObject()) return *value;
858 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
859
860 // Check if the given name is an array index.
861 uint32_t index;
862 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000863 HandleScope scope;
864 Handle<Object> result = SetElement(receiver, index, value);
865 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866 return *value;
867 }
868
869 // Lookup the property locally in the receiver.
870 LookupResult lookup;
871 receiver->LocalLookup(*name, &lookup);
872
873 // Update inline cache and stub cache.
874 if (FLAG_use_ic && lookup.IsLoaded()) {
875 UpdateCaches(&lookup, state, receiver, name, value);
876 }
877
878 // Set the property.
879 return receiver->SetProperty(*name, *value, NONE);
880}
881
882
883void StoreIC::UpdateCaches(LookupResult* lookup,
884 State state,
885 Handle<JSObject> receiver,
886 Handle<String> name,
887 Handle<Object> value) {
888 ASSERT(lookup->IsLoaded());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000889 // Skip JSGlobalProxy.
890 if (receiver->IsJSGlobalProxy()) return;
891
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000892 // Bail out if we didn't find a result.
893 if (!lookup->IsValid() || !lookup->IsCacheable()) return;
894
895 // If the property is read-only, we leave the IC in its current
896 // state.
897 if (lookup->IsReadOnly()) return;
898
899 // If the property has a non-field type allowing map transitions
900 // where there is extra room in the object, we leave the IC in its
901 // current state.
902 PropertyType type = lookup->type();
903
904 // Compute the code stub for this store; used for rewriting to
905 // monomorphic state and making sure that the code stub is in the
906 // stub cache.
907 Object* code = NULL;
908 switch (type) {
909 case FIELD: {
910 code = StubCache::ComputeStoreField(*name, *receiver,
911 lookup->GetFieldIndex());
912 break;
913 }
914 case MAP_TRANSITION: {
915 if (lookup->GetAttributes() != NONE) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916 HandleScope scope;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000917 ASSERT(type == MAP_TRANSITION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000918 Handle<Map> transition(lookup->GetTransitionMap());
919 int index = transition->PropertyIndexFor(*name);
920 code = StubCache::ComputeStoreField(*name, *receiver, index, *transition);
921 break;
922 }
923 case CALLBACKS: {
924 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return;
925 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
926 if (v8::ToCData<Address>(callback->setter()) == 0) return;
927 code = StubCache::ComputeStoreCallback(*name, *receiver, callback);
928 break;
929 }
930 case INTERCEPTOR: {
931 code = StubCache::ComputeStoreInterceptor(*name, *receiver);
932 break;
933 }
934 default:
935 return;
936 }
937
938 // If we're unable to compute the stub (not enough memory left), we
939 // simply avoid updating the caches.
940 if (code->IsFailure()) return;
941
942 // Patch the call site depending on the state of the cache.
943 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
944 set_target(Code::cast(code));
945 } else if (state == MONOMORPHIC) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000946 // Only move to mega morphic if the target changes.
947 if (target() != Code::cast(code)) set_target(megamorphic_stub());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000948 }
949
950#ifdef DEBUG
951 TraceIC("StoreIC", name, state, target());
952#endif
953}
954
955
956Object* KeyedStoreIC::Store(State state,
957 Handle<Object> object,
958 Handle<Object> key,
959 Handle<Object> value) {
960 if (key->IsSymbol()) {
961 Handle<String> name = Handle<String>::cast(key);
962
963 // If the object is undefined or null it's illegal to try to set any
964 // properties on it; throw a TypeError in that case.
965 if (object->IsUndefined() || object->IsNull()) {
966 return TypeError("non_object_property_store", object, name);
967 }
968
969 // Ignore stores where the receiver is not a JSObject.
970 if (!object->IsJSObject()) return *value;
971 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
972
973 // Check if the given name is an array index.
974 uint32_t index;
975 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000976 HandleScope scope;
977 Handle<Object> result = SetElement(receiver, index, value);
978 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000979 return *value;
980 }
981
982 // Lookup the property locally in the receiver.
983 LookupResult lookup;
984 receiver->LocalLookup(*name, &lookup);
985
986 // Update inline cache and stub cache.
987 if (FLAG_use_ic && lookup.IsLoaded()) {
988 UpdateCaches(&lookup, state, receiver, name, value);
989 }
990
991 // Set the property.
992 return receiver->SetProperty(*name, *value, NONE);
993 }
994
995 // Do not use ICs for objects that require access checks (including
996 // the global object).
997 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000998 ASSERT(!(use_ic && object->IsJSGlobalProxy()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999
1000 if (use_ic) set_target(generic_stub());
1001
1002 // Set the property.
1003 return Runtime::SetObjectProperty(object, key, value, NONE);
1004}
1005
1006
1007void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
1008 State state,
1009 Handle<JSObject> receiver,
1010 Handle<String> name,
1011 Handle<Object> value) {
1012 ASSERT(lookup->IsLoaded());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001013
1014 // Skip JSGlobalProxy.
1015 if (receiver->IsJSGlobalProxy()) return;
1016
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017 // Bail out if we didn't find a result.
1018 if (!lookup->IsValid() || !lookup->IsCacheable()) return;
1019
1020 // If the property is read-only, we leave the IC in its current
1021 // state.
1022 if (lookup->IsReadOnly()) return;
1023
1024 // If the property has a non-field type allowing map transitions
1025 // where there is extra room in the object, we leave the IC in its
1026 // current state.
1027 PropertyType type = lookup->type();
1028
1029 // Compute the code stub for this store; used for rewriting to
1030 // monomorphic state and making sure that the code stub is in the
1031 // stub cache.
1032 Object* code = NULL;
1033
1034 switch (type) {
1035 case FIELD: {
1036 code = StubCache::ComputeKeyedStoreField(*name, *receiver,
1037 lookup->GetFieldIndex());
1038 break;
1039 }
1040 case MAP_TRANSITION: {
1041 if (lookup->GetAttributes() == NONE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001042 HandleScope scope;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001043 ASSERT(type == MAP_TRANSITION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001044 Handle<Map> transition(lookup->GetTransitionMap());
1045 int index = transition->PropertyIndexFor(*name);
1046 code = StubCache::ComputeKeyedStoreField(*name, *receiver,
1047 index, *transition);
1048 break;
1049 }
1050 // fall through.
1051 }
1052 default: {
1053 // Always rewrite to the generic case so that we do not
1054 // repeatedly try to rewrite.
1055 code = generic_stub();
1056 break;
1057 }
1058 }
1059
1060 // If we're unable to compute the stub (not enough memory left), we
1061 // simply avoid updating the caches.
1062 if (code->IsFailure()) return;
1063
1064 // Patch the call site depending on the state of the cache. Make
1065 // sure to always rewrite from monomorphic to megamorphic.
1066 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
1067 if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
1068 set_target(Code::cast(code));
1069 } else if (state == MONOMORPHIC) {
1070 set_target(megamorphic_stub());
1071 }
1072
1073#ifdef DEBUG
1074 TraceIC("KeyedStoreIC", name, state, target());
1075#endif
1076}
1077
1078
1079// ----------------------------------------------------------------------------
1080// Static IC stub generators.
1081//
1082
1083// Used from ic_<arch>.cc.
1084Object* CallIC_Miss(Arguments args) {
1085 NoHandleAllocation na;
1086 ASSERT(args.length() == 2);
1087 CallIC ic;
1088 IC::State state = IC::StateFrom(ic.target(), args[0]);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001089 Object* result =
1090 ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
1091 if (state != UNINITIALIZED_IN_LOOP || !result->IsJSFunction())
1092 return result;
1093
1094 // Compile the function with the knowledge that it's called from
1095 // within a loop. This enables further optimization of the function.
1096 HandleScope scope;
1097 Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result));
1098 if (!function->is_compiled()) CompileLazyInLoop(function, CLEAR_EXCEPTION);
1099 return *function;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001100}
1101
1102
1103void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) {
1104 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
1105}
1106
1107
1108void CallIC::GeneratePreMonomorphic(MacroAssembler* masm, int argc) {
1109 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
1110}
1111
1112
1113void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
1114 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
1115}
1116
1117
1118// Used from ic_<arch>.cc.
1119Object* LoadIC_Miss(Arguments args) {
1120 NoHandleAllocation na;
1121 ASSERT(args.length() == 2);
1122 LoadIC ic;
1123 IC::State state = IC::StateFrom(ic.target(), args[0]);
1124 return ic.Load(state, args.at<Object>(0), args.at<String>(1));
1125}
1126
1127
1128void LoadIC::GenerateInitialize(MacroAssembler* masm) {
1129 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
1130}
1131
1132
1133void LoadIC::GeneratePreMonomorphic(MacroAssembler* masm) {
1134 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
1135}
1136
1137
1138// Used from ic_<arch>.cc
1139Object* KeyedLoadIC_Miss(Arguments args) {
1140 NoHandleAllocation na;
1141 ASSERT(args.length() == 2);
1142 KeyedLoadIC ic;
1143 IC::State state = IC::StateFrom(ic.target(), args[0]);
1144 return ic.Load(state, args.at<Object>(0), args.at<Object>(1));
1145}
1146
1147
1148void KeyedLoadIC::GenerateInitialize(MacroAssembler* masm) {
1149 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
1150}
1151
1152
1153void KeyedLoadIC::GeneratePreMonomorphic(MacroAssembler* masm) {
1154 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss)));
1155}
1156
1157
1158// Used from ic_<arch>.cc.
1159Object* StoreIC_Miss(Arguments args) {
1160 NoHandleAllocation na;
1161 ASSERT(args.length() == 3);
1162 StoreIC ic;
1163 IC::State state = IC::StateFrom(ic.target(), args[0]);
1164 return ic.Store(state, args.at<Object>(0), args.at<String>(1),
1165 args.at<Object>(2));
1166}
1167
1168
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001169// Extend storage is called in a store inline cache when
1170// it is necessary to extend the properties array of a
1171// JSObject.
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001172Object* SharedStoreIC_ExtendStorage(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001173 NoHandleAllocation na;
1174 ASSERT(args.length() == 3);
1175
1176 // Convert the parameters
1177 JSObject* object = JSObject::cast(args[0]);
1178 Map* transition = Map::cast(args[1]);
1179 Object* value = args[2];
1180
1181 // Check the object has run out out property space.
1182 ASSERT(object->HasFastProperties());
1183 ASSERT(object->map()->unused_property_fields() == 0);
1184
1185 // Expand the properties array.
1186 FixedArray* old_storage = object->properties();
1187 int new_unused = transition->unused_property_fields();
1188 int new_size = old_storage->length() + new_unused + 1;
1189 Object* result = old_storage->CopySize(new_size);
1190 if (result->IsFailure()) return result;
1191 FixedArray* new_storage = FixedArray::cast(result);
1192 new_storage->set(old_storage->length(), value);
1193
ager@chromium.org32912102009-01-16 10:38:43 +00001194 // Set the new property value and do the map transition.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001195 object->set_properties(new_storage);
1196 object->set_map(transition);
1197
1198 // Return the stored value.
1199 return value;
1200}
1201
1202
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001203void StoreIC::GenerateInitialize(MacroAssembler* masm) {
1204 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
1205}
1206
1207
1208void StoreIC::GenerateMiss(MacroAssembler* masm) {
1209 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
1210}
1211
1212
1213// Used from ic_<arch>.cc.
1214Object* KeyedStoreIC_Miss(Arguments args) {
1215 NoHandleAllocation na;
1216 ASSERT(args.length() == 3);
1217 KeyedStoreIC ic;
1218 IC::State state = IC::StateFrom(ic.target(), args[0]);
1219 return ic.Store(state, args.at<Object>(0), args.at<Object>(1),
1220 args.at<Object>(2));
1221}
1222
1223
1224void KeyedStoreIC::GenerateInitialize(MacroAssembler* masm) {
1225 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss)));
1226}
1227
1228
1229void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
1230 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss)));
1231}
1232
1233
1234static Address IC_utilities[] = {
1235#define ADDR(name) FUNCTION_ADDR(name),
1236 IC_UTIL_LIST(ADDR)
1237 NULL
1238#undef ADDR
1239};
1240
1241
1242Address IC::AddressFromUtilityId(IC::UtilityId id) {
1243 return IC_utilities[id];
1244}
1245
1246
1247} } // namespace v8::internal