📄 ic.cc.svn-base
字号:
// setting the monomorphic state. code = StubCache::ComputeCallPreMonomorphic(argc); } else if (state == MONOMORPHIC) { code = StubCache::ComputeCallMegamorphic(argc); } else { // Compute monomorphic stub. switch (lookup->type()) { case FIELD: { int index = lookup->GetFieldIndex(); code = StubCache::ComputeCallField(argc, *name, *object, lookup->holder(), index); break; } case CONSTANT_FUNCTION: { // Get the constant function and compute the code stub for this // call; used for rewriting to monomorphic state and making sure // that the code stub is in the stub cache. JSFunction* function = lookup->GetConstantFunction(); code = StubCache::ComputeCallConstant(argc, *name, *object, lookup->holder(), function); break; } case NORMAL: { // There is only one shared stub for calling normalized // properties. It does not traverse the prototype chain, so the // property must be found in the receiver for the stub to be // applicable. if (!object->IsJSObject()) return; Handle<JSObject> receiver = Handle<JSObject>::cast(object); if (lookup->holder() != *receiver) return; code = StubCache::ComputeCallNormal(argc, *name, *receiver); break; } case INTERCEPTOR: { code = StubCache::ComputeCallInterceptor(argc, *name, *object, lookup->holder()); break; } default: return; } } // If we're unable to compute the stub (not enough memory left), we // simply avoid updating the caches. if (code->IsFailure()) return; // Patch the call site depending on the state of the cache. if (state == UNINITIALIZED || state == PREMONOMORPHIC || state == MONOMORPHIC || state == MONOMORPHIC_PROTOTYPE_FAILURE) { set_target(Code::cast(code)); }#ifdef DEBUG TraceIC("CallIC", name, state, target());#endif}Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) { // If the object is undefined or null it's illegal to try to get any // of its properties; throw a TypeError in that case. if (object->IsUndefined() || object->IsNull()) { return TypeError("non_object_property_load", object, name); } if (FLAG_use_ic) { // Use specialized code for getting the length of strings. if (object->IsString() && name->Equals(Heap::length_symbol())) {#ifdef DEBUG if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");#endif Code* target = NULL; if (object->IsShortString()) { target = Builtins::builtin(Builtins::LoadIC_ShortStringLength); } else if (object->IsMediumString()) { target = Builtins::builtin(Builtins::LoadIC_MediumStringLength); } else { ASSERT(object->IsLongString()); target = Builtins::builtin(Builtins::LoadIC_LongStringLength); } set_target(target); StubCache::Set(*name, HeapObject::cast(*object)->map(), target); return Smi::FromInt(String::cast(*object)->length()); } // Use specialized code for getting the length of arrays. if (object->IsJSArray() && name->Equals(Heap::length_symbol())) {#ifdef DEBUG if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");#endif Code* target = Builtins::builtin(Builtins::LoadIC_ArrayLength); set_target(target); StubCache::Set(*name, HeapObject::cast(*object)->map(), target); return JSArray::cast(*object)->length(); } // Use specialized code for getting prototype of functions. if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) {#ifdef DEBUG if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");#endif Code* target = Builtins::builtin(Builtins::LoadIC_FunctionPrototype); set_target(target); StubCache::Set(*name, HeapObject::cast(*object)->map(), target); return Accessors::FunctionGetPrototype(*object, 0); } } // Check if the name is trivially convertible to an index and get // the element if so. uint32_t index; if (name->AsArrayIndex(&index)) return object->GetElement(index); // Named lookup in the object. LookupResult lookup; object->Lookup(*name, &lookup); // If lookup is invalid, check if we need to throw an exception. if (!lookup.IsValid()) { if (FLAG_strict || is_contextual()) { return ReferenceError("not_defined", name); } String* class_name = object->IsJSObject() ? Handle<JSObject>::cast(object)->class_name() : Heap::empty_string(); LOG(SuspectReadEvent(*name, class_name)); USE(class_name); } // Update inline cache and stub cache. if (FLAG_use_ic && lookup.IsLoaded()) { UpdateCaches(&lookup, state, object, name); } PropertyAttributes attr; if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { // Get the property. Object* result = object->GetProperty(*object, &lookup, *name, &attr); if (result->IsFailure()) return result; // If the property is not present, check if we need to throw an // exception. if (attr == ABSENT && is_contextual()) { return ReferenceError("not_defined", name); } return result; } // Get the property. return object->GetProperty(*object, &lookup, *name, &attr);}void LoadIC::UpdateCaches(LookupResult* lookup, State state, Handle<Object> object, Handle<String> name) { ASSERT(lookup->IsLoaded()); // Bail out if we didn't find a result. if (!lookup->IsValid() || !lookup->IsCacheable()) return; // Loading properties from values is not common, so don't try to // deal with non-JS objects here. if (!object->IsJSObject()) return; Handle<JSObject> receiver = Handle<JSObject>::cast(object); // Compute the code stub for this load. Object* code = NULL; if (state == UNINITIALIZED) { // This is the first time we execute this inline cache. // Set the target to the pre monomorphic stub to delay // setting the monomorphic state. code = pre_monomorphic_stub(); } else { // Compute monomorphic stub. switch (lookup->type()) { case FIELD: { code = StubCache::ComputeLoadField(*name, *receiver, lookup->holder(), lookup->GetFieldIndex()); break; } case CONSTANT_FUNCTION: { Object* constant = lookup->GetConstantFunction(); code = StubCache::ComputeLoadConstant(*name, *receiver, lookup->holder(), constant); break; } case NORMAL: { // There is only one shared stub for loading normalized // properties. It does not traverse the prototype chain, so the // property must be found in the receiver for the stub to be // applicable. if (lookup->holder() != *receiver) return; code = StubCache::ComputeLoadNormal(*name, *receiver); break; } case CALLBACKS: { if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); if (v8::ToCData<Address>(callback->getter()) == 0) return; code = StubCache::ComputeLoadCallback(*name, *receiver, lookup->holder(), callback); break; } case INTERCEPTOR: { code = StubCache::ComputeLoadInterceptor(*name, *receiver, lookup->holder()); break; } default: return; } } // If we're unable to compute the stub (not enough memory left), we // simply avoid updating the caches. if (code->IsFailure()) return; // Patch the call site depending on the state of the cache. if (state == UNINITIALIZED || state == PREMONOMORPHIC || state == MONOMORPHIC_PROTOTYPE_FAILURE) { set_target(Code::cast(code)); } else if (state == MONOMORPHIC) { set_target(megamorphic_stub()); }#ifdef DEBUG TraceIC("LoadIC", name, state, target());#endif}Object* KeyedLoadIC::Load(State state, Handle<Object> object, Handle<Object> key) { if (key->IsSymbol()) { Handle<String> name = Handle<String>::cast(key); // If the object is undefined or null it's illegal to try to get any // of its properties; throw a TypeError in that case. if (object->IsUndefined() || object->IsNull()) { return TypeError("non_object_property_load", object, name); } if (FLAG_use_ic) { // Use specialized code for getting the length of strings. if (object->IsString() && name->Equals(Heap::length_symbol())) { Handle<String> string = Handle<String>::cast(object); Object* code = NULL; if (string->IsShortString()) { code = StubCache::ComputeKeyedLoadShortStringLength(*name, *string); } else if (string->IsMediumString()) { code = StubCache::ComputeKeyedLoadMediumStringLength(*name, *string); } else { ASSERT(string->IsLongString()); code = StubCache::ComputeKeyedLoadLongStringLength(*name, *string); } if (code->IsFailure()) return code; set_target(Code::cast(code));#ifdef DEBUG TraceIC("KeyedLoadIC", name, state, target());#endif return Smi::FromInt(string->length()); } // Use specialized code for getting the length of arrays. if (object->IsJSArray() && name->Equals(Heap::length_symbol())) { Handle<JSArray> array = Handle<JSArray>::cast(object); Object* code = StubCache::ComputeKeyedLoadArrayLength(*name, *array); if (code->IsFailure()) return code; set_target(Code::cast(code));#ifdef DEBUG TraceIC("KeyedLoadIC", name, state, target());#endif return JSArray::cast(*object)->length(); } // Use specialized code for getting prototype of functions. if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) { Handle<JSFunction> function = Handle<JSFunction>::cast(object); Object* code = StubCache::ComputeKeyedLoadFunctionPrototype(*name, *function); if (code->IsFailure()) return code; set_target(Code::cast(code));#ifdef DEBUG TraceIC("KeyedLoadIC", name, state, target());#endif return Accessors::FunctionGetPrototype(*object, 0); } } // Check if the name is trivially convertible to an index and get // the element or char if so. uint32_t index = 0; if (name->AsArrayIndex(&index)) { HandleScope scope; // Rewrite to the generic keyed load stub. if (FLAG_use_ic) set_target(generic_stub()); return Runtime::GetElementOrCharAt(object, index); } // Named lookup. LookupResult lookup; object->Lookup(*name, &lookup); // If lookup is invalid, check if we need to throw an exception. if (!lookup.IsValid()) { if (FLAG_strict || is_contextual()) { return ReferenceError("not_defined", name); } } // Update the inline cache. if (FLAG_use_ic && lookup.IsLoaded()) { UpdateCaches(&lookup, state, object, name); } PropertyAttributes attr; if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { // Get the property. Object* result = object->GetProperty(*object, &lookup, *name, &attr); if (result->IsFailure()) return result; // If the property is not present, check if we need to throw an // exception. if (attr == ABSENT && is_contextual()) { return ReferenceError("not_defined", name); } return result; } return object->GetProperty(*object, &lookup, *name, &attr); } // Do not use ICs for objects that require access checks (including // the global object). bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); if (use_ic) set_target(generic_stub()); // Get the property. return Runtime::GetObjectProperty(object, key);}void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, Handle<Object> object, Handle<String> name) { ASSERT(lookup->IsLoaded()); // Bail out if we didn't find a result. if (!lookup->IsValid() || !lookup->IsCacheable()) return; if (!object->IsJSObject()) return; Handle<JSObject> receiver = Handle<JSObject>::cast(object); // Compute the code stub for this load. Object* code = NULL; if (state == UNINITIALIZED) { // This is the first time we execute this inline cache. // Set the target to the pre monomorphic stub to delay // setting the monomorphic state. code = pre_monomorphic_stub(); } else { // Compute a monomorphic stub. switch (lookup->type()) { case FIELD: { code = StubCache::ComputeKeyedLoadField(*name, *receiver, lookup->holder(), lookup->GetFieldIndex()); break; } case CONSTANT_FUNCTION: { Object* constant = lookup->GetConstantFunction(); code = StubCache::ComputeKeyedLoadConstant(*name, *receiver, lookup->holder(), constant); break; } case CALLBACKS: { if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); if (v8::ToCData<Address>(callback->getter()) == 0) return; code = StubCache::ComputeKeyedLoadCallback(*name, *receiver, lookup->holder(), callback); break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -