예제 #1
0
파일: translator.cpp 프로젝트: MaxSem/hhvm
const Func* lookupImmutableMethod(const Class* cls, const StringData* name,
                                  bool& magicCall, bool staticLookup,
                                  const Func* ctxFunc,
                                  bool exactClass) {
  if (!cls) return nullptr;
  if (cls->attrs() & AttrInterface) return nullptr;
  auto ctx = ctxFunc->cls();
  if (!(cls->attrs() & AttrUnique)) {
    if (!ctx || !ctx->classof(cls)) {
      return nullptr;
    }
  }

  const Func* func;
  LookupResult res = staticLookup ?
    g_context->lookupClsMethod(func, cls, name, nullptr, ctx, false) :
    g_context->lookupObjMethod(func, cls, name, ctx, false);

  if (res == LookupResult::MethodNotFound) return nullptr;

  if (func->isAbstract()) return nullptr;

  assertx(res == LookupResult::MethodFoundWithThis ||
          res == LookupResult::MethodFoundNoThis ||
          (staticLookup ?
           res == LookupResult::MagicCallStaticFound :
           res == LookupResult::MagicCallFound));

  magicCall =
    res == LookupResult::MagicCallStaticFound ||
    res == LookupResult::MagicCallFound;

  if (staticLookup) {
    if (magicCall) {
      if (ctx && !ctxFunc->isStatic() &&
          (ctx->classof(cls) || cls->classof(ctx))) {
        // we might need to call __call instead
        return nullptr;
      }
      if (!exactClass && !(cls->attrs() & AttrNoOverride)) {
        // there might be a derived class which defines the method
        return nullptr;
      }
    } else if (!exactClass) {
      if (!func->isImmutableFrom(cls)) return nullptr;
    }
  } else if (!exactClass && !(func->attrs() & AttrPrivate)) {
    if (magicCall) {
      if (!(cls->attrs() & AttrNoOverride)) {
        return nullptr;
      }
    } else if (!func->isImmutableFrom(cls)) {
      return nullptr;
    }
  }
  return func;
}
예제 #2
0
파일: oostruct.c 프로젝트: barak/lush
at *send_message(at *classname, at *obj, at *method, at *args)
{
   class_t *cl = classof(obj);

   /* find superclass */
   if (classname) {
      ifn (SYMBOLP(classname))
         error(NIL, "not a class name", classname);
      while (cl && cl->classname != classname)
         cl = cl->super;
      ifn (cl)
         error(NIL, "cannot find class", classname);
   }
   /* send */
   ifn (SYMBOLP(method))
      error(NIL, "not a method name", method);
   struct hashelem *hx = _getmethod(cl, method);
   if (hx)
      return call_method(obj, hx, args);
   else if (method == at_pname) // special method?
      return NEW_STRING(cl->name(obj));

   /* send -unknown */
   hx = _getmethod(cl, at_unknown);
   if (hx) {
      at *arg = new_cons(method, new_cons(args, NIL));
      return call_method(obj, hx, arg);
   }
   /* fail */
   error(NIL, "method not found", method);
}
예제 #3
0
파일: oostruct.c 프로젝트: barak/lush
void lush_delete(at *p)
{
   if (!p || ZOMBIEP(p))
      return;

   class_t *cl = classof(p);
   if (cl->dontdelete)
      error(NIL, "cannot delete this object", p);
   
   run_notifiers(p);
   
   if (cl->has_compiled_part) {
      assert(isa(p, object_class));
      /* OO objects may have two parts          */
      /* lush_delete has to delete both of them */
      object_t *obj = Mptr(p);
      struct CClass_object *cobj = obj->cptr;
      oostruct_dispose(obj);
      cobj->Vtbl->Cdestroy(cobj);
      
   } else {
      if (Class(p)->dispose)
         Mptr(p) = Class(p)->dispose(Mptr(p));
      else
         Mptr(p) = NULL;
   }
   zombify(p);
}
예제 #4
0
파일: oostruct.c 프로젝트: barak/lush
bool isa(at *p, const class_t *cl)
{
   class_t *c = classof(p);
   while (c && c != cl)
      c = c->super;
   return c == cl;
}
예제 #5
0
파일: event.c 프로젝트: barak/lush
/* process_pending_events --
 * Process currently pending events
 * by calling event-hook and event-idle
 * until no events are left.
 */
void process_pending_events(void)
{
   MM_ENTER;
   int timer_fired = 0;
   call_spoll();
   at *hndl = ev_peek();
   for(;;) {
      while (hndl) {
         /* Call the handler method <handle> */
         at *event = event_get(hndl, true);
         if (CONSP(event)) {
            class_t *cl = classof(hndl);
            at *m = getmethod(cl, at_handle);
            if (m) {
               at *args = new_cons(quote(event), NIL);
               send_message(NIL, hndl, at_handle, args);
            }
         }
         /* Check for more events */
         call_spoll();
         hndl = ev_peek();
      }

      /* Check for timer events */
      if (timer_fired)
         break;
      timer_fire();
      timer_fired = 1;
      hndl = ev_peek();
   }
   MM_EXIT;
}
예제 #6
0
bool InliningDecider::canInlineAt(SrcKey callSK, const Func* callee) const {
  if (!callee ||
      !RuntimeOption::EvalHHIREnableGenTimeInlining ||
      RuntimeOption::EvalJitEnableRenameFunction ||
      callee->attrs() & AttrInterceptable) {
    return false;
  }

  if (callee->cls()) {
    if (!classHasPersistentRDS(callee->cls())) {
      // if the callee's class is not persistent, its still ok
      // to use it if we're jitting into a method of a subclass
      auto ctx = callSK.func()->cls();
      if (!ctx || !ctx->classof(callee->cls())) {
        return false;
      }
    }
  } else {
    auto const handle = callee->funcHandle();
    if (handle == rds::kInvalidHandle || !rds::isPersistentHandle(handle)) {
      // if the callee isn't persistent, its still ok to
      // use it if its defined at the top level in the same
      // unit as the caller
      if (callee->unit() != callSK.unit() || !callee->top()) {
        return false;
      }
    }
  }

  // If inlining was disabled... don't inline.
  if (m_disabled) return false;

  // TODO(#3331014): We have this hack until more ARM codegen is working.
  if (arch() == Arch::ARM) return false;

  // We can only inline at normal FCalls.
  if (callSK.op() != Op::FCall &&
      callSK.op() != Op::FCallD) {
    return false;
  }

  // Don't inline from resumed functions.  The inlining mechanism doesn't have
  // support for these---it has no way to redefine stack pointers relative to
  // the frame pointer, because in a resumed function the frame pointer points
  // into the heap instead of into the eval stack.
  if (callSK.resumed()) return false;

  // TODO(#4238160): Inlining into pseudomain callsites is still buggy.
  if (callSK.func()->isPseudoMain()) return false;

  if (!isCalleeInlinable(callSK, callee) || !checkNumArgs(callSK, callee)) {
    return false;
  }

  return true;
}
예제 #7
0
bool filename_t::equals (object_t* other) {
  ___CBTPUSH;

  bool result = this == other;
  if (!result) {
    result = other->getClass () == classof (filename_t) && strcmp (((filename_t*) other)->m_name, m_name) == 0;
  }

  ___CBTPOP;
  return result;
}
예제 #8
0
icu::TimeZone* IntlTimeZone::ParseArg(CVarRef arg,
                                      const String& funcname,
                                      intl_error &err) {
  String tzstr;

  if (arg.isNull()) {
    tzstr = f_date_default_timezone_get();
  } else if (arg.isObject()) {
    auto objarg = arg.toObject();
    auto cls = objarg->getVMClass();
    auto IntlTimeZone_Class = Unit::lookupClass(s_IntlTimeZone.get());
    if (IntlTimeZone_Class &&
        ((cls == IntlTimeZone_Class) || cls->classof(IntlTimeZone_Class))) {
      return IntlTimeZone::Get(objarg)->timezone()->clone();
    }
    if (auto dtz = objarg.getTyped<c_DateTimeZone>(true, true)) {
      tzstr = dtz->t_getname();
    } else {
      tzstr = arg.toString();
    }
  } else {
    tzstr = arg.toString();
  }

  UErrorCode error = U_ZERO_ERROR;
  icu::UnicodeString id;
  if (!Intl::ustring_from_char(id, tzstr, error)) {
    err.code = error;
    err.custom_error_message = funcname +
      String(": Time zone identifier given is not a "
             "valid UTF-8 string", CopyString);
    return nullptr;
  }
  auto ret = icu::TimeZone::createTimeZone(id);
  if (!ret) {
    err.code = U_MEMORY_ALLOCATION_ERROR;
    err.custom_error_message = funcname +
      String(": could not create time zone", CopyString);
    return nullptr;
  }
  icu::UnicodeString gottenId;
  if (ret->getID(gottenId) != id) {
    err.code = U_ILLEGAL_ARGUMENT_ERROR;
    err.custom_error_message = funcname +
      String(": no such time zone: '", CopyString) + arg.toString() + "'";
    delete ret;
    return nullptr;
  }
  return ret;
}
예제 #9
0
icu::TimeZone* IntlTimeZone::ParseArg(const Variant& arg,
                                      const String& funcname,
                                      IntlError* err) {
  String tzstr;

  if (arg.isNull()) {
    tzstr = f_date_default_timezone_get();
  } else if (arg.isObject()) {
    auto objarg = arg.toObject();
    auto cls = objarg->getVMClass();
    auto IntlTimeZone_Class = Unit::lookupClass(s_IntlTimeZone.get());
    if (IntlTimeZone_Class &&
        ((cls == IntlTimeZone_Class) || cls->classof(IntlTimeZone_Class))) {
      return IntlTimeZone::Get(objarg.get())->timezone()->clone();
    }
    if (objarg.instanceof(DateTimeZoneData::getClass())) {
      auto* dtz = Native::data<DateTimeZoneData>(objarg.get());
      tzstr = dtz->getName();
    } else {
      tzstr = arg.toString();
    }
  } else {
    tzstr = arg.toString();
  }

  UErrorCode error = U_ZERO_ERROR;
  icu::UnicodeString id;
  if (!ustring_from_char(id, tzstr, error)) {
    err->setError(error, "%s: Time zone identifier given is not a "
                         "valid UTF-8 string", funcname.c_str());
    return nullptr;
  }
  auto ret = icu::TimeZone::createTimeZone(id);
  if (!ret) {
    err->setError(U_MEMORY_ALLOCATION_ERROR,
                  "%s: could not create time zone", funcname.c_str());
    return nullptr;
  }
  icu::UnicodeString gottenId;
  if (ret->getID(gottenId) != id) {
    err->setError(U_ILLEGAL_ARGUMENT_ERROR,
                  "%s: no such time zone: '%s'",
                  funcname.c_str(), arg.toString().c_str());
    delete ret;
    return nullptr;
  }
  return ret;
}
예제 #10
0
/* process_pending_events --
   Process currently pending events
   by calling event-hook and event-idle
   until no events are left. */
void 
process_pending_events(void)
{
  at *hndl;
  at *event;
  int timer_fired = 0;
  call_spoll();
  hndl = ev_peek();
  for(;;)
    {
      while (hndl)
        {
          /* Call the handler method <handle> */
          LOCK(hndl);
          event = event_get(hndl, TRUE);
          if (CONSP(event))
            {
              at *cl = classof(hndl);
              if (EXTERNP(cl, &class_class))
                {
                  at *m = checksend(cl->Object, at_handle);
                  if (m)
                    {
                      at *args = new_cons(event,NIL);
                      UNLOCK(m);
                      argeval_ptr = eval_nothing;
                      m = send_message(NIL,hndl,at_handle,args);
                      argeval_ptr = eval_std;
                      UNLOCK(args);
                    }
                  UNLOCK(m);
                }
              UNLOCK(cl);
            }
          UNLOCK(event);
          UNLOCK(hndl);
          /* Check for more events */
          call_spoll();
          hndl = ev_peek();
        }
      /* Check for timer events */
      if (timer_fired)
        break;
      timer_fire();
      timer_fired = 1;
      hndl = ev_peek();
    }
}
예제 #11
0
const Func* lookupImmutableCtor(const Class* cls, const Class* ctx) {
  if (!cls) return nullptr;

  auto const func = cls->getCtor();
  if (func && !(func->attrs() & AttrPublic)) {
    auto fcls = func->cls();
    if (fcls != ctx) {
      if (!ctx) return nullptr;
      if ((func->attrs() & AttrPrivate) ||
          !(ctx->classof(fcls) || fcls->classof(ctx))) {
        return nullptr;
      }
    }
  }

  return func;
}
예제 #12
0
파일: oostruct.c 프로젝트: barak/lush
static object_t *oostruct_dispose(object_t *obj)
{
   /* oostruct gets called only once */
   assert(!ZOMBIEP(obj->backptr));

   obj->next_unreachable = NULL;

   int oldready = error_doc.ready_to_an_error;
   error_doc.ready_to_an_error = true;
   struct lush_context mycontext;
   context_push(&mycontext);
   
   int errflag = sigsetjmp(context->error_jump,1);
   if (errflag==0) {
      /* call all destructors for interpreted part */
      /* destructors for compiled part are called  */
      /* by finalizer for compiled part            */
      at *f = NIL;
      class_t *cl = Class(obj->backptr);
      while (cl) {
         struct hashelem *hx = _getmethod(cl, at_destroy);
         cl = cl->super;
         if (! hx)
            break;
         else if (hx->function == f)
            continue;
         else if (classof(hx->function) == dh_class)
            break;
         call_method(obj->backptr, hx, NIL);
         f = hx->function;
      }
   }
   
   context_pop();
   error_doc.ready_to_an_error = oldready;
   if (obj->cptr)
      obj->cptr->__lptr = NULL;
   zombify(obj->backptr);
   
   if (errflag)
      siglongjmp(context->error_jump, -1L);

   return obj;
}
예제 #13
0
TypeConstraint applyConstraint(TypeConstraint tc, const TypeConstraint newTc) {
  tc.category = std::max(newTc.category, tc.category);

  if (newTc.wantArrayKind()) tc.setWantArrayKind();

  if (newTc.wantClass()) {
    if (tc.wantClass()) {
      // It only makes sense to constrain tc with a class that's related to its
      // existing class, and we want to preserve the more derived of the two.
      auto cls1 = tc.desiredClass();
      auto cls2 = newTc.desiredClass();
      tc.setDesiredClass(cls1->classof(cls2) ? cls1 : cls2);
    } else {
      tc.setDesiredClass(newTc.desiredClass());
    }
  }

  return tc;
}
예제 #14
0
파일: type.cpp 프로젝트: skynet/hhvm
TEST(Type, SpecializedObjects) {
  auto const A = SystemLib::s_IteratorClass;
  auto const B = SystemLib::s_TraversableClass;
  EXPECT_TRUE(A->classof(B));

  auto const obj = Type::Obj;
  auto const exactA = obj.specializeExact(A);
  auto const exactB = obj.specializeExact(B);
  auto const subA = obj.specialize(A);
  auto const subB = obj.specialize(B);

  EXPECT_EQ(exactA.getClass(), A);
  EXPECT_EQ(subA.getClass(), A);

  EXPECT_EQ(exactA.getExactClass(), A);
  EXPECT_EQ(subA.getExactClass(), nullptr);

  EXPECT_LE(exactA, exactA);
  EXPECT_LE(subA, subA);

  EXPECT_LT(exactA, obj);
  EXPECT_LT(subA, obj);

  EXPECT_LE(Type::Bottom, subA);
  EXPECT_LE(Type::Bottom, exactA);

  EXPECT_LT(exactA, subA);

  EXPECT_LT(exactA, subB);
  EXPECT_LT(subA, subB);

  EXPECT_FALSE(exactA <= exactB);
  EXPECT_FALSE(subA <= exactB);

  EXPECT_EQ(exactA & subA, exactA);
  EXPECT_EQ(subA & exactA, exactA);
  EXPECT_EQ(exactB & subB, exactB);
  EXPECT_EQ(subB & exactB, exactB);

  EXPECT_EQ(Type::Obj, Type::Obj - subA);  // conservative
  EXPECT_EQ(subA, subA - exactA);  // conservative
}
예제 #15
0
GuardConstraint applyConstraint(GuardConstraint gc,
                                GuardConstraint newGc) {
  gc.category = std::max(newGc.category, gc.category);

  if (newGc.wantArrayKind()) gc.setWantArrayKind();

  if (newGc.wantClass()) {
    if (gc.wantClass()) {
      // It only makes sense to constrain gc with a class that's related to its
      // existing class, and we want to preserve the more derived of the two.
      auto cls1 = gc.desiredClass();
      auto cls2 = newGc.desiredClass();
      gc.setDesiredClass(cls1->classof(cls2) ? cls1 : cls2);
    } else {
      gc.setDesiredClass(newGc.desiredClass());
    }
  }

  return gc;
}
예제 #16
0
파일: oostruct.c 프로젝트: barak/lush
void oostruct_setslot(at *p, at *prop, at *val)
{
   at *slot = Car(prop);
   ifn (SYMBOLP(slot))
      error(NIL, "not a slot name", slot);
   prop = Cdr(prop);

   object_t *obj = Mptr(p);
   class_t *cl = Class(obj->backptr);
   for(int i=0; i<cl->num_slots; i++)
      if (slot == cl->slots[i]) {
         if (prop)
            setslot(&obj->slots[i], prop, val);
         else if (i<cl->num_cslots) {
            class_t *cl = classof(obj->slots[i]);
            cl->setslot(obj->slots[i], NIL, val);
         } else
            obj->slots[i] = val;
         return;
      }
   error(NIL, "not a slot", slot);
}
예제 #17
0
const Func* lookupImmutableCtor(const Class* cls, const Class* ctx) {
  if (!cls || RuntimeOption::EvalJitEnableRenameFunction) return nullptr;
  if (!(cls->attrs() & AttrUnique)) {
    if (!ctx || !ctx->classof(cls)) {
      return nullptr;
    }
  }

  auto const func = cls->getCtor();
  if (func && !(func->attrs() & AttrPublic)) {
    auto fcls = func->cls();
    if (fcls != ctx) {
      if (!ctx) return nullptr;
      if ((func->attrs() & AttrPrivate) ||
          !(ctx->classof(fcls) || fcls->classof(ctx))) {
        return nullptr;
      }
    }
  }

  return func;
}
예제 #18
0
// Called by the proxy whenever its breakpoint list is updated.
// Since this intended to be called when user input is received, it is not
// performance critical. Also, in typical scenarios, the list is short.
void phpSetBreakPoints(Eval::DebuggerProxy* proxy) {
  Eval::BreakPointInfoPtrVec bps;
  proxy->getBreakPoints(bps);
  for (unsigned int i = 0; i < bps.size(); i++) {
    Eval::BreakPointInfoPtr bp = bps[i];
    bp->m_bindState = Eval::BreakPointInfo::Unknown;
    auto className = bp->getClass();
    if (!className.empty()) {
      auto clsName = makeStaticString(className);
      auto cls = Unit::lookupClass(clsName);
      if (cls == nullptr) continue;
      bp->m_bindState = Eval::BreakPointInfo::KnownToBeInvalid;
      size_t numFuncs = cls->numMethods();
      if (numFuncs == 0) continue;
      auto methodName = bp->getFunction();
      Func* const* funcs = cls->methods();
      for (size_t i = 0; i < numFuncs; ++i) {
        auto f = funcs[i];
        if (!matchFunctionName(methodName, f)) continue;
        bp->m_bindState = Eval::BreakPointInfo::KnownToBeValid;
        addBreakPointFuncEntry(f);
        break;
      }
      //TODO: what about superclass methods accessed via the derived class?
      //Task 2527229.
      continue;
    }
    auto funcName = bp->getFuncName();
    if (!funcName.empty()) {
      auto fName = makeStaticString(funcName);
      Func* f = Unit::lookupFunc(fName);
      if (f == nullptr) continue;
      if (f->hasGeneratorAsBody() && !f->isAsync()) {
        // This function is a generator, and it's the original
        // function which has been turned into a stub which creates a
        // continuation. We want to set the breakpoint on the
        // continuation function instead.
        fName = makeStaticString(funcName + "$continuation");
        f = Unit::lookupFunc(fName);
        if (f == nullptr) continue;
      }
      bp->m_bindState = Eval::BreakPointInfo::KnownToBeValid;
      addBreakPointFuncEntry(f);
      continue;
    }
    auto fileName = bp->m_file;
    if (!fileName.empty()) {
      for (EvaledFilesMap::const_iterator it =
           g_vmContext->m_evaledFiles.begin();
           it != g_vmContext->m_evaledFiles.end(); ++it) {
        auto efile = it->second;
        if (!Eval::BreakPointInfo::MatchFile(fileName, efile->getFileName())) {
          continue;
        }
        addBreakPointInUnit(bp, efile->unit());
        break;
      }
      continue;
    }
    auto exceptionClassName = bp->getExceptionClass();
    if (exceptionClassName == "@") {
      bp->m_bindState = Eval::BreakPointInfo::KnownToBeValid;
      continue;
    } else if (!exceptionClassName.empty()) {
      auto expClsName = makeStaticString(exceptionClassName);
      auto cls = Unit::lookupClass(expClsName);
      if (cls != nullptr) {
        auto baseClsName = makeStaticString("Exception");
        auto baseCls = Unit::lookupClass(baseClsName);
        if (baseCls != nullptr) {
          if (cls->classof(baseCls)) {
            bp->m_bindState = Eval::BreakPointInfo::KnownToBeValid;
          } else {
            bp->m_bindState = Eval::BreakPointInfo::KnownToBeInvalid;
          }
        }
      }
      continue;
    } else {
      continue;
    }
    // If we get here, the break point is of a type that does
    // not need to be explicitly enabled in the VM. For example
    // a break point that get's triggered when the server starts
    // to process a page request.
    bp->m_bindState = Eval::BreakPointInfo::KnownToBeValid;
  }
}
예제 #19
0
void proxySetBreakPoints(DebuggerProxy* proxy) {
  std::vector<BreakPointInfoPtr> bps;
  proxy->getBreakPoints(bps);
  for (unsigned int i = 0; i < bps.size(); i++) {
    BreakPointInfoPtr bp = bps[i];
    bp->m_bindState = BreakPointInfo::Unknown;
    auto className = bp->getClass();
    if (!className.empty()) {
      auto clsName = makeStaticString(className);
      auto cls = Unit::lookupClass(clsName);
      if (cls == nullptr) continue;
      bp->m_bindState = BreakPointInfo::KnownToBeInvalid;
      size_t numFuncs = cls->numMethods();
      if (numFuncs == 0) continue;
      auto methodName = bp->getFunction();
      for (size_t i = 0; i < numFuncs; ++i) {
        auto f = cls->getMethod(i);
        if (!matchFunctionName(methodName, f)) continue;
        bp->m_bindState = BreakPointInfo::KnownToBeValid;
        phpAddBreakPointFuncEntry(f);
        break;
      }
      // TODO(#2527229): what about superclass methods accessed via the derived
      // class?
      continue;
    }
    auto funcName = bp->getFuncName();
    if (!funcName.empty()) {
      auto fName = makeStaticString(funcName);
      Func* f = Unit::lookupFunc(fName);
      if (f == nullptr) continue;
      bp->m_bindState = BreakPointInfo::KnownToBeValid;
      phpAddBreakPointFuncEntry(f);
      continue;
    }
    auto fileName = bp->m_file;
    if (!fileName.empty()) {
      for (auto& kv : g_context->m_evaledFiles) {
        auto const unit = kv.second;
        if (!BreakPointInfo::MatchFile(fileName,
                            unit->filepath()->toCppString())) {
          continue;
        }
        addBreakPointInUnit(bp, unit);
        break;
      }
      continue;
    }
    auto exceptionClassName = bp->getExceptionClass();
    if (exceptionClassName == "@") {
      bp->m_bindState = BreakPointInfo::KnownToBeValid;
      continue;
    } else if (!exceptionClassName.empty()) {
      auto expClsName = makeStaticString(exceptionClassName);
      auto cls = Unit::lookupClass(expClsName);
      if (cls != nullptr) {
        auto baseClsName = makeStaticString("Exception");
        auto baseCls = Unit::lookupClass(baseClsName);
        if (baseCls != nullptr) {
          if (cls->classof(baseCls)) {
            bp->m_bindState = BreakPointInfo::KnownToBeValid;
          } else {
            bp->m_bindState = BreakPointInfo::KnownToBeInvalid;
          }
        }
      }
      continue;
    } else {
      continue;
    }
    // If we get here, the break point is of a type that does
    // not need to be explicitly enabled in the VM. For example
    // a break point that get's triggered when the server starts
    // to process a page request.
    bp->m_bindState = BreakPointInfo::KnownToBeValid;
  }
}