⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ic.cc.svn-base

📁 Google浏览器V8内核代码
💻 SVN-BASE
📖 第 1 页 / 共 3 页
字号:
// Copyright 2006-2008 the V8 project authors. All rights reserved.// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met:////     * Redistributions of source code must retain the above copyright//       notice, this list of conditions and the following disclaimer.//     * Redistributions in binary form must reproduce the above//       copyright notice, this list of conditions and the following//       disclaimer in the documentation and/or other materials provided//       with the distribution.//     * Neither the name of Google Inc. nor the names of its//       contributors may be used to endorse or promote products derived//       from this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#include "v8.h"#include "accessors.h"#include "api.h"#include "arguments.h"#include "execution.h"#include "ic-inl.h"#include "runtime.h"#include "stub-cache.h"namespace v8 { namespace internal {#ifdef DEBUGstatic char TransitionMarkFromState(IC::State state) {  switch (state) {    case UNINITIALIZED: return '0';    case PREMONOMORPHIC: return '0';    case MONOMORPHIC: return '1';    case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';    case MEGAMORPHIC: return 'N';    // We never see the debugger states here, because the state is    // computed from the original code - not the patched code. Let    // these cases fall through to the unreachable code below.    case DEBUG_BREAK: break;    case DEBUG_PREPARE_STEP_IN: break;  }  UNREACHABLE();  return 0;}void IC::TraceIC(const char* type,                 Handle<String> name,                 State old_state,                 Code* new_target) {  if (FLAG_trace_ic) {    State new_state = StateFrom(new_target, Heap::undefined_value());    PrintF("[%s (%c->%c) ", type,           TransitionMarkFromState(old_state),           TransitionMarkFromState(new_state));    name->Print();    PrintF("]\n");  }}#endifIC::IC(FrameDepth depth) {  // To improve the performance of the (much used) IC code, we unfold  // a few levels of the stack frame iteration code. This yields a  // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag.  const Address entry = Top::c_entry_fp(Top::GetCurrentThread());  Address* pc_address =      reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);  Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);  // If there's another JavaScript frame on the stack, we need to look  // one frame further down the stack to find the frame pointer and  // the return address stack slot.  if (depth == EXTRA_CALL_FRAME) {    const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;    pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);    fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);  }#ifdef DEBUG  StackFrameIterator it;  for (int i = 0; i < depth + 1; i++) it.Advance();  StackFrame* frame = it.frame();  ASSERT(fp == frame->fp() && pc_address == frame->pc_address());#endif  fp_ = fp;  pc_address_ = pc_address;}Address IC::OriginalCodeAddress() {  HandleScope scope;  // Compute the JavaScript frame for the frame pointer of this IC  // structure. We need this to be able to find the function  // corresponding to the frame.  StackFrameIterator it;  while (it.frame()->fp() != this->fp()) it.Advance();  JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());  // Find the function on the stack and both the active code for the  // function and the original code.  JSFunction* function = JSFunction::cast(frame->function());  Handle<SharedFunctionInfo> shared(function->shared());  Code* code = shared->code();  ASSERT(Debug::HasDebugInfo(shared));  Code* original_code = Debug::GetDebugInfo(shared)->original_code();  ASSERT(original_code->IsCode());  // Get the address of the call site in the active code. This is the  // place where the call to DebugBreakXXX is and where the IC  // normally would be.  Address addr = pc() - Assembler::kTargetAddrToReturnAddrDist;  // Return the address in the original code. This is the place where  // the call which has been overwriten by the DebugBreakXXX resides  // and the place where the inline cache system should look.  int delta = original_code->instruction_start() - code->instruction_start();  return addr + delta;}IC::State IC::StateFrom(Code* target, Object* receiver) {  IC::State state = target->ic_state();  if (state != MONOMORPHIC) return state;  if (receiver->IsUndefined() || receiver->IsNull()) return state;  Map* map = GetCodeCacheMapForObject(receiver);  // Decide whether the inline cache failed because of changes to the  // receiver itself or changes to one of its prototypes.  //  // If there are changes to the receiver itself, the map of the  // receiver will have changed and the current target will not be in  // the receiver map's code cache.  Therefore, if the current target  // is in the receiver map's code cache, the inline cache failed due  // to prototype check failure.  int index = map->IndexInCodeCache(target);  if (index >= 0) {    // For keyed load/store, the most likely cause of cache failure is    // that the key has changed.  We do not distinguish between    // prototype and non-prototype failures for keyed access.    Code::Kind kind = target->kind();    if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) {      return MONOMORPHIC;    }    // Remove the target from the code cache to avoid hitting the same    // invalid stub again.    map->RemoveFromCodeCache(index);    return MONOMORPHIC_PROTOTYPE_FAILURE;  }  // The builtins object is special.  It only changes when JavaScript  // builtins are loaded lazily.  It is important to keep inline  // caches for the builtins object monomorphic.  Therefore, if we get  // an inline cache miss for the builtins object after lazily loading  // JavaScript builtins, we return uninitialized as the state to  // force the inline cache back to monomorphic state.  if (receiver->IsJSBuiltinsObject()) {    return UNINITIALIZED;  }  return MONOMORPHIC;}RelocInfo::Mode IC::ComputeMode() {  Address addr = address();  Code* code = Code::cast(Heap::FindCodeObject(addr));  for (RelocIterator it(code, RelocInfo::kCodeTargetMask);       !it.done(); it.next()) {    RelocInfo* info = it.rinfo();    if (info->pc() == addr) return info->rmode();  }  UNREACHABLE();  return RelocInfo::NONE;}Failure* IC::TypeError(const char* type,                       Handle<Object> object,                       Handle<String> name) {  HandleScope scope;  Handle<Object> args[2] = { name, object };  Handle<Object> error = Factory::NewTypeError(type, HandleVector(args, 2));  return Top::Throw(*error);}Failure* IC::ReferenceError(const char* type, Handle<String> name) {  HandleScope scope;  Handle<Object> error =      Factory::NewReferenceError(type, HandleVector(&name, 1));  return Top::Throw(*error);}void IC::Clear(Address address) {  Code* target = GetTargetAtAddress(address);  // Don't clear debug break inline cache as it will remove the break point.  if (target->ic_state() == DEBUG_BREAK) return;  switch (target->kind()) {    case Code::LOAD_IC: return LoadIC::Clear(address, target);    case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target);    case Code::STORE_IC: return StoreIC::Clear(address, target);    case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target);    case Code::CALL_IC: return CallIC::Clear(address, target);    default: UNREACHABLE();  }}void CallIC::Clear(Address address, Code* target) {  if (target->ic_state() == UNINITIALIZED) return;  Code* code = StubCache::FindCallInitialize(target->arguments_count());  SetTargetAtAddress(address, code);}void KeyedLoadIC::Clear(Address address, Code* target) {  if (target->ic_state() == UNINITIALIZED) return;  SetTargetAtAddress(address, initialize_stub());}void LoadIC::Clear(Address address, Code* target) {  if (target->ic_state() == UNINITIALIZED) return;  SetTargetAtAddress(address, initialize_stub());}void StoreIC::Clear(Address address, Code* target) {  if (target->ic_state() == UNINITIALIZED) return;  SetTargetAtAddress(address, initialize_stub());}void KeyedStoreIC::Clear(Address address, Code* target) {  if (target->ic_state() == UNINITIALIZED) return;  SetTargetAtAddress(address, initialize_stub());}Object* CallIC::TryCallAsFunction(Object* object) {  HandleScope scope;  Handle<Object> target(object);  Handle<Object> delegate = Execution::GetFunctionDelegate(target);  if (delegate->IsJSFunction()) {    // Patch the receiver and use the delegate as the function to    // invoke. This is used for invoking objects as if they were    // functions.    const int argc = this->target()->arguments_count();    StackFrameLocator locator;    JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);    int index = frame->ComputeExpressionsCount() - (argc + 1);    frame->SetExpression(index, *target);  }  return *delegate;}Object* CallIC::LoadFunction(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_call", object, name);  }  Object* result = Heap::the_hole_value();  // Check if the name is trivially convertible to an index and get  // the element if so.  uint32_t index;  if (name->AsArrayIndex(&index)) {    result = object->GetElement(index);    if (result->IsJSFunction()) return result;    // Try to find a suitable function delegate for the object at hand.    result = TryCallAsFunction(result);    if (result->IsJSFunction()) return result;    // Otherwise, it will fail in the lookup step.  }  // Lookup the property in the object.  LookupResult lookup;  object->Lookup(*name, &lookup);  if (!lookup.IsValid()) {    // If the object does not have the requested property, check which    // exception we need to throw.    if (is_contextual()) {      return ReferenceError("not_defined", name);    }    return TypeError("undefined_method", object, name);  }  // Lookup is valid: Update inline cache and stub cache.  if (FLAG_use_ic && lookup.IsLoaded()) {    UpdateCaches(&lookup, state, object, name);  }  if (lookup.type() == INTERCEPTOR) {    // Get the property.    PropertyAttributes attr;    result = object->GetProperty(*name, &attr);    if (result->IsFailure()) return result;    // If the object does not have the requested property, check which    // exception we need to throw.    if (attr == ABSENT) {      if (is_contextual()) {        return ReferenceError("not_defined", name);      }      return TypeError("undefined_method", object, name);    }  } else {    // Lookup is valid and no interceptors are involved. Get the    // property.    result = object->GetProperty(*name);    if (result->IsFailure()) return result;  }  ASSERT(result != Heap::the_hole_value());  if (result->IsJSFunction()) {    // Check if there is an optimized (builtin) version of the function.    // Ignored this will degrade performance for Array.prototype.{push,pop}.    // Please note we only return the optimized function iff    // the JSObject has FastElements.    if (object->IsJSObject() && JSObject::cast(*object)->HasFastElements()) {      Object* opt = Top::LookupSpecialFunction(JSObject::cast(*object),                                               lookup.holder(),                                               JSFunction::cast(result));      if (opt->IsJSFunction()) return opt;    }    // If performing debug step into then flood this function with one-shot    // break points if it is called from where step into was requested.    if (Debug::StepInActive() && fp() == Debug::step_in_fp()) {      // Don't allow step into functions in the native context.      if (JSFunction::cast(result)->context()->global() !=          Top::context()->builtins()) {        HandleScope scope;        Handle<SharedFunctionInfo> shared(JSFunction::cast(result)->shared());        Debug::FloodWithOneShot(shared);      }    }    return result;  }  // Try to find a suitable function delegate for the object at hand.  result = TryCallAsFunction(result);  return result->IsJSFunction() ?      result : TypeError("property_not_function", object, name);}void CallIC::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;  // Compute the number of arguments.  int argc = target()->arguments_count();  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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -