예제 #1
0
/*
 * The CreateCl opcode is specified as not being allowed before the
 * class it creates exists, and closure classes are always unique.
 *
 * This means even if we're not in RepoAuthoritative mode, as long as
 * this code is reachable it will always use the same closure Class*,
 * so we can just burn it into the TC without using RDS.
 */
void emitCreateCl(HTS& env, int32_t numParams, const StringData* clsName) {
  auto const cls = Unit::lookupClassOrUniqueClass(clsName);
  auto const invokeFunc = cls->lookupMethod(s_uuinvoke.get());
  auto const clonedFunc = invokeFunc->cloneAndSetClass(
    const_cast<Class*>(curClass(env))
  );
  assert(cls && (cls->attrs() & AttrUnique));

  auto const closure = allocObjFast(env, cls);
  gen(env, IncRef, closure);

  auto const ctx = [&]{
    if (!curClass(env)) return cns(env, nullptr);
    auto const ldctx = gen(env, LdCtx, fp(env));
    if (invokeFunc->attrs() & AttrStatic) {
      return gen(env, ConvClsToCctx, gen(env, LdClsCtx, ldctx));
    }
    gen(env, IncRefCtx, ldctx);
    return ldctx;
  }();
  gen(env, StClosureCtx, closure, ctx);
  gen(env, StClosureFunc, FuncData(clonedFunc), closure);

  SSATmp* args[numParams];
  for (int32_t i = 0; i < numParams; ++i) {
    args[numParams - i - 1] = popF(env);
  }

  int32_t propId = 0;
  for (; propId < numParams; ++propId) {
    gen(
      env,
      StClosureArg,
      PropByteOffset(cls->declPropOffset(propId)),
      closure,
      args[propId]
    );
  }

  // Closure static variables are per instance, and need to start
  // uninitialized.  After numParams use vars, the remaining instance
  // properties hold any static locals.
  assert(cls->numDeclProperties() ==
         clonedFunc->numStaticLocals() + numParams);
  for (int32_t numDeclProperties = cls->numDeclProperties();
      propId < numDeclProperties;
      ++propId) {
    gen(
      env,
      StClosureArg,
      PropByteOffset(cls->declPropOffset(propId)),
      closure,
      cns(env, Type::Uninit)
    );
  }

  push(env, closure);
}
예제 #2
0
/*
 * Check instanceof using the superclass vector on the end of the Class entry.
 */
void cgExtendsClass(IRLS& env, const IRInstruction* inst) {
  auto const extra = inst->extra<ExtendsClassData>();
  auto const dst = dstLoc(env, inst, 0).reg();
  auto const lhs = srcLoc(env, inst, 0).reg();
  auto const rhsCls = extra->cls;
  auto& v = vmain(env);

  assertx(rhsCls != nullptr);

  // Check whether `lhs' points to a subclass of rhsCls, set `d' with the
  // boolean result, and return `d'.
  auto check_subclass = [&](Vreg d) {
    if (rhsCls->classVecLen() == 1) {
      // Every class has at least one entry in its class vec, so there's no
      // need to check the length.
      return check_clsvec(v, d, lhs, rhsCls, 1);
    }
    assertx(rhsCls->classVecLen() > 1);

    // Check the length of the class vectors.  If the candidate's is at least
    // as long as the potential base (`rhsCls'), it might be a subclass.
    auto const sf = v.makeReg();
    emitCmpVecLen(v, sf, static_cast<int32_t>(rhsCls->classVecLen()),
                  lhs[Class::classVecLenOff()]);
    return check_subcls(v, sf, d, lhs, rhsCls, rhsCls->classVecLen());
  };

  if (rhsCls->attrs() & AttrAbstract ||
      (extra->strictLikely && !(rhsCls->attrs() & AttrNoOverride))) {
    // If the test must be extended, or the hint says it's probably not an
    // exact match, don't check for the same class.
    check_subclass(dst);
    return;
  }

  // Test if it is the exact same class.
  // TODO(#2044801): We should be doing this control flow at the IR level.
  auto const sf = v.makeReg();
  emitCmpLowPtr<Class>(v, sf, v.cns(rhsCls), lhs);

  if (rhsCls->attrs() & AttrNoOverride) {
    // If the test class cannot be extended, we only need to do the same-class
    // check, never the subclass check.
    v << setcc{CC_E, sf, dst};
    return;
  }

  cond(
    v, CC_E, sf, dst,
    [&] (Vout& v) { return v.cns(true); },
    [&] (Vout& v) { return check_subclass(v.makeReg()); }
  );
}
void QgsMapToolOffsetCurve::canvasReleaseEvent( QMouseEvent * e )
{
  Q_UNUSED( e );
  QgsVectorLayer* vlayer = currentVectorLayer();
  if ( !vlayer )
  {
    deleteRubberBandAndGeometry();
    return;
  }

  if ( !mGeometryModified )
  {
    deleteRubberBandAndGeometry();
    vlayer->destroyEditCommand();
    return;
  }

  if ( mMultiPartGeometry )
  {
    mModifiedGeometry.convertToMultiType();
  }

  vlayer->beginEditCommand( tr( "Offset curve" ) );

  bool editOk;
  if ( mSourceLayerId == vlayer->id() && !mForceCopy )
  {
    editOk = vlayer->changeGeometry( mModifiedFeature, &mModifiedGeometry );
  }
  else
  {
    QgsFeature f;
    f.setGeometry( mModifiedGeometry );

    //add empty values for all fields (allows inserting attribute values via the feature form in the same session)
    QgsAttributes attrs( vlayer->pendingFields().count() );
    const QgsFields& fields = vlayer->pendingFields();
    for ( int idx = 0; idx < fields.count(); ++idx )
    {
      attrs[idx] = QVariant();
    }
    f.setAttributes( attrs );
    editOk = vlayer->addFeature( f );
  }

  if ( editOk )
  {
    vlayer->endEditCommand();
  }
  else
  {
    vlayer->destroyEditCommand();
  }

  deleteRubberBandAndGeometry();
  deleteDistanceItem();
  delete mSnapVertexMarker; mSnapVertexMarker = 0;
  mForceCopy = false;
  mCanvas->refresh();
}
예제 #4
0
void
Properties::parsePropertyKeyValue(const std::string &property,
				  const char kvpsep,
				  const char kvsep) {
    size_t coma = 0, curPos = 0;
    std::string attrs(property);

    Utils::trim(attrs);
    size_t len = attrs.size();

    while(coma < len) {
	coma = attrs.find(kvpsep, curPos);
	std::string attrPair = attrs.substr(curPos, coma - curPos);

	while(coma < len && attrs.at(coma) == kvpsep) coma++;

	curPos = coma;

	Utils::trim(attrPair);
	if(attrPair.size() == 0)
	    continue;

	size_t pipe = attrPair.find(kvsep);
	if(pipe != std::string::npos) {
	    std::string key = attrPair.substr(0, pipe);
	    std::string value = attrPair.substr(pipe + 1);

	    Utils::trim(key);
	    Utils::trim(value);
	    set(key, value);
	}
    }
    return;
}
예제 #5
0
void c_Closure::init(int numArgs, ActRec* ar, TypedValue* sp) {
  auto const invokeFunc = getVMClass()->lookupMethod(s_uuinvoke.get());

  m_thisOrClass = ar->m_this;
  if (ar->hasThis()) {
    if (invokeFunc->attrs() & AttrStatic) {
      // Only set the class for static closures.
      m_thisOrClass = reinterpret_cast<ObjectData*>(
        reinterpret_cast<intptr_t>(ar->getThis()->getVMClass()) | 1LL
      );
    } else {
      ar->getThis()->incRefCount();
    }
  }

  // Change my __invoke's m_cls to be the same as my creator's
  Class* scope = ar->m_func->cls();
  m_func = invokeFunc->cloneAndSetClass(scope);

  // copy the props to instance variables
  assert(m_cls->numDeclProperties() == numArgs);
  TypedValue* beforeCurUseVar = sp + numArgs;
  TypedValue* curProperty = propVec();
  for (int i = 0; i < numArgs; i++) {
    // teleport the references in here so we don't incref
    tvCopy(*--beforeCurUseVar, *curProperty++);
  }
}
예제 #6
0
파일: type.cpp 프로젝트: StetHD/hhvm
Type typeFromTV(const TypedValue* tv) {
  assertx(tv->m_type == KindOfClass || tvIsPlausible(*tv));

  if (tv->m_type == KindOfObject) {
    auto const cls = tv->m_data.pobj->getVMClass();

    // We only allow specialization on classes that can't be overridden for
    // now.  If this changes, then this will need to specialize on sub object
    // types instead.
    if (!cls || !(cls->attrs() & AttrNoOverride)) return TObj;
    return Type::ExactObj(cls);
  }

  if (isArrayType(tv->m_type)) {
    return Type::Array(tv->m_data.parr->kind());
  }

  auto outer = tv->m_type;
  auto inner = KindOfUninit;

  if (outer == KindOfPersistentString) outer = KindOfString;
  if (outer == KindOfRef) {
    inner = tv->m_data.pref->tv()->m_type;
    if (inner == KindOfPersistentString) inner = KindOfString;
    else if (inner == KindOfPersistentArray) inner = KindOfArray;
  }
  return Type(outer, inner);
}
예제 #7
0
	void IAttributeData::deserialise(LoadingState *state, data::Table *data)
	{
		Handle<data::Table> attrs(data->at<data::Table>("attributes"));
		if (attrs)
		{
			mAttributes = attrs;
		}
	}
예제 #8
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;
}
예제 #9
0
/* static */ void
ChromeUtils::OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
                                      const dom::OriginAttributesDictionary& aAttrs,
                                      nsCString& aSuffix)

{
  GenericOriginAttributes attrs(aAttrs);
  attrs.CreateSuffix(aSuffix);
}
예제 #10
0
/* static */ bool
ChromeUtils::OriginAttributesMatchPattern(dom::GlobalObject& aGlobal,
                                          const dom::OriginAttributesDictionary& aAttrs,
                                          const dom::OriginAttributesPatternDictionary& aPattern)
{
  GenericOriginAttributes attrs(aAttrs);
  OriginAttributesPattern pattern(aPattern);
  return pattern.Matches(attrs);
}
예제 #11
0
static void setHotFuncAttr() {
  static bool synced = false;
  if (synced) return;

  Lock lock(syncLock);
  if (synced) return;

  /*
   * s_treadmill forces any Funcs that are being destroyed to go through a
   * treadmill pass, to make sure we won't try to dereference something that's
   * being pulled out from under us.
   */
  Func::s_treadmill = true;
  SCOPE_EXIT {
    Func::s_treadmill = false;
  };

  if (RuntimeOption::EvalHotFuncCount) {
    std::priority_queue<FuncHotness,
                        std::vector<FuncHotness>,
                        bool(*)(const FuncHotness& a, const FuncHotness& b)>
      queue(comp);

    Func::getFuncVec().foreach([&](const Func* f) {
      if (!f) return;
      auto const profCounter = [&]() -> uint32_t {
        FuncProfileCounters::const_accessor acc;
        if (s_func_counters.find(acc, f->getFuncId())) {
          return acc->second;
        }
        return 0;
      }();
      auto fh = FuncHotness(f, profCounter);
      if (queue.size() >= RuntimeOption::EvalHotFuncCount) {
        if (!comp(fh, queue.top())) return;
        queue.pop();
      }
      queue.push(fh);
    });

    while (queue.size()) {
      auto f = queue.top().first;
      queue.pop();
      const_cast<Func*>(f)->setAttrs(f->attrs() | AttrHot);
    }
  }

  // We won't need the counters anymore.  But there might be requests in flight
  // that still thought they were profiling, so we need to clear it on the
  // treadmill.
  Treadmill::enqueue([&] {
    FuncProfileCounters newMap(0);
    swap(s_func_counters, newMap);
  });

  synced = true;
}
예제 #12
0
void handlePossibleStackOverflow(ActRec* calleeAR) {
  assert_native_stack_aligned();

  // If it's not an overflow, it was probably a surprise flag trip.  But we
  // can't assert that it is because background threads are allowed to clear
  // surprise bits concurrently, so it could be cleared again by now.
  if (!checkCalleeStackOverflow(calleeAR)) return;
  auto const func = calleeAR->func();

  /*
   * Stack overflows in this situation are a slightly different case than
   * handleStackOverflow:
   *
   * A function prologue already did all the work to prepare to enter the
   * function, but then it found out it didn't have enough room on the stack.
   * It may even have written uninits deeper than the stack base (but we limit
   * it to sSurprisePageSize, so it's harmless).
   *
   * Most importantly, it might have pulled args /off/ the eval stack and
   * shoved them into an ExtraArgs on the calleeAR, or into an array for a
   * variadic capture param.  We need to get things into an appropriate state
   * for handleStackOverflow to be able to synchronize things to throw from the
   * PC of the caller's FCall.
   *
   * We don't actually need to make sure the stack is the right depth for the
   * FCall: the unwinder will expect to see a pre-live ActRec (and we'll set it
   * up so it will), but it doesn't care how many args (or what types of args)
   * are below it on the stack.
   *
   * It is tempting to try to free the ExtraArgs structure here, but it's ok to
   * not to:
   *
   *     o We're about to raise an uncatchable fatal, which will end the
   *       request.  We leak ExtraArgs in other similar situations for this too
   *       (e.g. if called via FCallArray and then a stack overflow happens).
   *
   *     o If we were going to free the ExtraArgs structure, we'd need to make
   *       sure we can re-enter the VM right now, which means performing a
   *       manual fixup first.  (We aren't in a situation where we can do a
   *       normal VMRegAnchor fixup right now.)  But moreover we shouldn't be
   *       running destructors if a fatal is happening anyway, so we don't want
   *       that either.
   *
   * So, all that boils down to this: we ignore the extra args field (the
   * unwinder will not consult the ExtraArgs field because it believes the
   * ActRec is pre-live).  And set calleeAR->m_numArgs to indicate how many
   * things are actually on the stack (so handleStackOverflow knows what to set
   * the vmsp to)---we just set it to the function's numLocals, which might
   * mean decreffing some uninits unnecessarily, but that's ok.
   */

  if (debug && func->attrs() & AttrMayUseVV && calleeAR->getExtraArgs()) {
    calleeAR->trashVarEnv();
  }
  calleeAR->setNumArgs(calleeAR->m_func->numLocals());
  handleStackOverflow(calleeAR);
}
예제 #13
0
파일: main.cpp 프로젝트: wpbest/copperspice
static QVector<HB_CharAttributes> getCharAttributes(const QString &str, HB_Script script = HB_Script_Common)
{
    QVector<HB_CharAttributes> attrs(str.length());
    HB_ScriptItem item;
    item.pos = 0;
    item.length = str.length();
    item.script = script;
    HB_GetCharAttributes(str.utf16(), str.length(),
                         &item, 1,
                         attrs.data());
    return attrs;
}
예제 #14
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;
}
예제 #15
0
파일: native.cpp 프로젝트: isgiker/hhvm
TypedValue* methodWrapper(ActRec* ar) {
  auto func = ar->m_func;
  auto numArgs = func->numParams();
  auto numNonDefault = ar->numArgs();
  bool isStatic = func->isStatic();
  assert(!func->hasVariadicCaptureParam());
  TypedValue* args = ((TypedValue*)ar) - 1;
  TypedValue rv;
  rv.m_type = KindOfNull;

  if (LIKELY(numNonDefault == numArgs) ||
      LIKELY(nativeWrapperCheckArgs(ar))) {
    if (coerceFCallArgs(args, numArgs, numNonDefault, func)) {

      // Prepend a context arg for methods
      // KindOfClass when it's being called statically Foo::bar()
      // KindOfObject when it's being called on an instance $foo->bar()
      TypedValue ctx;
      if (ar->hasThis()) {
        if (isStatic) {
          throw_instance_method_fatal(getInvokeName(ar)->data());
        }
        ctx.m_type = KindOfObject;
        ctx.m_data.pobj = ar->getThis();
      } else {
        if (!isStatic) {
          throw_instance_method_fatal(getInvokeName(ar)->data());
        }
        ctx.m_type = KindOfClass;
        ctx.m_data.pcls = const_cast<Class*>(ar->getClass());
      }

      callFunc(func, &ctx, args, numArgs, rv);
    } else if (func->attrs() & AttrParamCoerceModeFalse) {
      rv.m_type = KindOfBoolean;
      rv.m_data.num = 0;
    }
  }

  assert(rv.m_type != KindOfUninit);
  if (isStatic) {
    frame_free_locals_no_this_inl(ar, func->numLocals(), &rv);
  } else {
    frame_free_locals_inl(ar, func->numLocals(), &rv);
  }
  tvCopy(rv, ar->m_r);
  return &ar->m_r;
}
예제 #16
0
파일: Sound.cpp 프로젝트: 304471720/spring
// try to get the maximum number of supported sounds, this is similar to code CSound::StartThread
// but should be more safe
int CSound::GetMaxMonoSources(ALCdevice* device, int maxSounds)
{
	ALCint size;
	alcGetIntegerv(device, ALC_ATTRIBUTES_SIZE, 1, &size);
	std::vector<ALCint> attrs(size);
	alcGetIntegerv(device, ALC_ALL_ATTRIBUTES, size, &attrs[0] );
	for (int i=0; i<attrs.size(); ++i){
		if (attrs[i] == ALC_MONO_SOURCES) {
			const int maxMonoSources = attrs.at(i + 1);
			if (maxMonoSources < maxSounds) {
				LOG_L(L_WARNING, "Hardware supports only %d Sound sources, MaxSounds=%d, using Hardware Limit", maxMonoSources, maxSounds);
			}
			return std::min(maxSounds, maxMonoSources);
		}
	}
	return maxSounds;
}
KoFilter::ConversionStatus PptxXmlCommentAuthorsReader::read_cmAuthor()
{
    READ_PROLOGUE

    QXmlStreamAttributes attrs( attributes() );

    READ_ATTR_WITHOUT_NS(id)
    READ_ATTR_WITHOUT_NS(name)

    d->context->authors.insert(id.toInt(), name);

    while (!atEnd()) {
        readNext();
        BREAK_IF_END_OF(CURRENT_EL)
//         if (isStartElement()) {
//             TRY_READ_IF(extLst)
//             ELSE_WRONG_FORMAT
//         }
    }

    READ_EPILOGUE
}
예제 #18
0
파일: xml.cpp 프로젝트: codeaudit/stencila
Node& Node::sanitize(const Whitelist& whitelist){
	// Element nodes get checked
	if(is_element()){
		// Is tag name allowed?
		bool ok = false;
		std::string tag = name();
		for(auto item : whitelist){
			if(tag==item.first){
				ok = true;
				// Are attribute names allowed?
				for(auto attr : attrs()){
					bool ok = false;
					for(auto allowed : item.second){
						if(attr==allowed){
							ok = true;
							break;
						}
					}
					// Attribute is not allowed...erase it
					if(not ok) erase(attr);
				}
				break;
			}
		}
		if(not ok) {
			// Tag name is not allowed... remove it from parent
			destroy();
		}
		else {
			// Tag name is allowed...check children
			for(Node& child : children()) child.sanitize(whitelist);
		}
	}
	// Document and text nodes are not checked, only their children (if any)
	else {
		for(Node& child : children()) child.sanitize(whitelist);
	}
	return *this;
}
예제 #19
0
파일: native.cpp 프로젝트: isgiker/hhvm
TypedValue* functionWrapper(ActRec* ar) {
  auto func = ar->m_func;
  auto numArgs = func->numParams();
  auto numNonDefault = ar->numArgs();
  assert(!func->hasVariadicCaptureParam());
  TypedValue* args = ((TypedValue*)ar) - 1;
  TypedValue rv;
  rv.m_type = KindOfNull;

  if (LIKELY(numNonDefault == numArgs) ||
      LIKELY(nativeWrapperCheckArgs(ar))) {
    if (coerceFCallArgs(args, numArgs, numNonDefault, func)) {
      callFunc(func, nullptr, args, numArgs, rv);
    } else if (func->attrs() & AttrParamCoerceModeFalse) {
      rv.m_type = KindOfBoolean;
      rv.m_data.num = 0;
    }
  }

  assert(rv.m_type != KindOfUninit);
  frame_free_locals_no_this_inl(ar, func->numLocals(), &rv);
  tvCopy(rv, ar->m_r);
  return &ar->m_r;
}
bool QgsGeometryAnalyzer::extent( QgsVectorLayer* layer,
                                  const QString& shapefileName,
                                  bool onlySelectedFeatures,
                                  QProgressDialog * )
{
  if ( !layer )
  {
    return false;
  }

  QgsVectorDataProvider* dp = layer->dataProvider();
  if ( !dp )
  {
    return false;
  }

  QgsWkbTypes::Type outputType = QgsWkbTypes::Polygon;
  QgsCoordinateReferenceSystem crs = layer->crs();

  QgsFields fields;
  fields.append( QgsField( QStringLiteral( "MINX" ), QVariant::Double ) );
  fields.append( QgsField( QStringLiteral( "MINY" ), QVariant::Double ) );
  fields.append( QgsField( QStringLiteral( "MAXX" ), QVariant::Double ) );
  fields.append( QgsField( QStringLiteral( "MAXY" ), QVariant::Double ) );
  fields.append( QgsField( QStringLiteral( "CNTX" ), QVariant::Double ) );
  fields.append( QgsField( QStringLiteral( "CNTY" ), QVariant::Double ) );
  fields.append( QgsField( QStringLiteral( "AREA" ), QVariant::Double ) );
  fields.append( QgsField( QStringLiteral( "PERIM" ), QVariant::Double ) );
  fields.append( QgsField( QStringLiteral( "HEIGHT" ), QVariant::Double ) );
  fields.append( QgsField( QStringLiteral( "WIDTH" ), QVariant::Double ) );

  QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), fields, outputType, crs );

  QgsRectangle rect;
  if ( onlySelectedFeatures )  // take only selection
  {
    rect = layer->boundingBoxOfSelected();
  }
  else
  {
    rect = layer->extent();
  }

  double minx = rect.xMinimum();
  double miny = rect.yMinimum();
  double maxx = rect.xMaximum();
  double maxy = rect.yMaximum();
  double height = rect.height();
  double width = rect.width();
  double cntx = minx + ( width / 2.0 );
  double cnty = miny + ( height / 2.0 );
  double area = width * height;
  double perim = ( 2 * width ) + ( 2 * height );

  QgsFeature feat;
  QgsAttributes attrs( 10 );
  attrs[0] = QVariant( minx );
  attrs[1] = QVariant( miny );
  attrs[2] = QVariant( maxx );
  attrs[3] = QVariant( maxy );
  attrs[4] = QVariant( cntx );
  attrs[5] = QVariant( cnty );
  attrs[6] = QVariant( area );
  attrs[7] = QVariant( perim );
  attrs[8] = QVariant( height );
  attrs[9] = QVariant( width );
  feat.setAttributes( attrs );
  feat.setGeometry( QgsGeometry::fromRect( rect ) );
  vWriter.addFeature( feat );
  return true;
}
예제 #21
0
already_AddRefed<nsIPrincipal>
PrincipalInfoToPrincipal(const PrincipalInfo& aPrincipalInfo,
                         nsresult* aOptionalResult)
{
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aPrincipalInfo.type() != PrincipalInfo::T__None);

  nsresult stackResult;
  nsresult& rv = aOptionalResult ? *aOptionalResult : stackResult;

  nsCOMPtr<nsIScriptSecurityManager> secMan =
    do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return nullptr;
  }

  nsCOMPtr<nsIPrincipal> principal;

  switch (aPrincipalInfo.type()) {
    case PrincipalInfo::TSystemPrincipalInfo: {
      rv = secMan->GetSystemPrincipal(getter_AddRefs(principal));
      if (NS_WARN_IF(NS_FAILED(rv))) {
        return nullptr;
      }

      return principal.forget();
    }

    case PrincipalInfo::TNullPrincipalInfo: {
      principal = do_CreateInstance(NS_NULLPRINCIPAL_CONTRACTID, &rv);
      if (NS_WARN_IF(NS_FAILED(rv))) {
        return nullptr;
      }

      return principal.forget();
    }

    case PrincipalInfo::TContentPrincipalInfo: {
      const ContentPrincipalInfo& info =
        aPrincipalInfo.get_ContentPrincipalInfo();

      nsCOMPtr<nsIURI> uri;
      rv = NS_NewURI(getter_AddRefs(uri), info.spec());
      if (NS_WARN_IF(NS_FAILED(rv))) {
        return nullptr;
      }

      if (info.appId() == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
        rv = secMan->GetSimpleCodebasePrincipal(uri, getter_AddRefs(principal));
      } else {
        // TODO: Bug 1167100 - User nsIPrincipal.originAttribute in ContentPrincipalInfo
        OriginAttributes attrs(info.appId(), info.isInBrowserElement());
        principal = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
        rv = principal ? NS_OK : NS_ERROR_FAILURE;
      }
      if (NS_WARN_IF(NS_FAILED(rv))) {
        return nullptr;
      }

      return principal.forget();
    }

    case PrincipalInfo::TExpandedPrincipalInfo: {
      const ExpandedPrincipalInfo& info = aPrincipalInfo.get_ExpandedPrincipalInfo();

      nsTArray< nsCOMPtr<nsIPrincipal> > whitelist;
      nsCOMPtr<nsIPrincipal> wlPrincipal;

      for (uint32_t i = 0; i < info.whitelist().Length(); i++) {
        wlPrincipal = PrincipalInfoToPrincipal(info.whitelist()[i], &rv);
        if (NS_WARN_IF(NS_FAILED(rv))) {
          return nullptr;
        }
        // append that principal to the whitelist
        whitelist.AppendElement(wlPrincipal);
      }

      nsRefPtr<nsExpandedPrincipal> expandedPrincipal = new nsExpandedPrincipal(whitelist);
      if (!expandedPrincipal) {
        NS_WARNING("could not instantiate expanded principal");
        return nullptr;
      }

      principal = expandedPrincipal;
      return principal.forget();
    }

    default:
      MOZ_CRASH("Unknown PrincipalInfo type!");
  }

  MOZ_CRASH("Should never get here!");
}
예제 #22
0
void cgCallBuiltin(IRLS& env, const IRInstruction* inst) {
  auto const extra = inst->extra<CallBuiltin>();
  auto const callee = extra->callee;
  auto const returnType = inst->typeParam();
  auto const funcReturnType = callee->returnType();
  auto const returnByValue = callee->isReturnByValue();

  auto const dstData = dstLoc(env, inst, 0).reg(0);
  auto const dstType = dstLoc(env, inst, 0).reg(1);

  auto& v = vmain(env);

  // Whether `t' is passed in/out of C++ as String&/Array&/Object&.
  auto const isReqPtrRef = [] (MaybeDataType t) {
    return isStringType(t) || isArrayLikeType(t) ||
           t == KindOfObject || t == KindOfResource;
  };

  if (FixupMap::eagerRecord(callee)) {
    auto const sp = srcLoc(env, inst, 1).reg();
    auto const spOffset = cellsToBytes(extra->spOffset.offset);
    auto const& marker = inst->marker();
    auto const pc = marker.fixupSk().unit()->entry() + marker.fixupBcOff();

    auto const synced_sp = v.makeReg();
    v << lea{sp[spOffset], synced_sp};
    emitEagerSyncPoint(v, pc, rvmtl(), srcLoc(env, inst, 0).reg(), synced_sp);
  }

  int returnOffset = rds::kVmMInstrStateOff +
                     offsetof(MInstrState, tvBuiltinReturn);
  auto args = argGroup(env, inst);

  if (!returnByValue) {
    if (isBuiltinByRef(funcReturnType)) {
      if (isReqPtrRef(funcReturnType)) {
        returnOffset += TVOFF(m_data);
      }
      // Pass the address of tvBuiltinReturn to the native function as the
      // location where it can construct the return Array, String, Object, or
      // Variant.
      args.addr(rvmtl(), returnOffset);
      args.indirect();
    }
  }

  // The srcs past the first two (sp and fp) are the arguments to the callee.
  auto srcNum = uint32_t{2};

  // Add the this_ or self_ argument for HNI builtins.
  if (callee->isMethod()) {
    if (callee->isStatic()) {
      args.ssa(srcNum);
      ++srcNum;
    } else {
      // Note that we don't support objects with vtables here (if they may need
      // a $this pointer adjustment).  This should be filtered out during irgen
      // or before.
      args.ssa(srcNum);
      ++srcNum;
    }
  }

  // Add the func_num_args() value if needed.
  if (callee->attrs() & AttrNumArgs) {
    // If `numNonDefault' is negative, this is passed as an src.
    if (extra->numNonDefault >= 0) {
      args.imm((int64_t)extra->numNonDefault);
    } else {
      args.ssa(srcNum);
      ++srcNum;
    }
  }

  // Add the positional arguments.
  for (uint32_t i = 0; i < callee->numParams(); ++i, ++srcNum) {
    auto const& pi = callee->params()[i];

    // Non-pointer and NativeArg args are passed by value.  String, Array,
    // Object, and Variant are passed by const&, i.e. a pointer to stack memory
    // holding the value, so we expect PtrToT types for these.  Pointers to
    // req::ptr types (String, Array, Object) need adjusting to point to
    // &ptr->m_data.
    if (TVOFF(m_data) && !pi.nativeArg && isReqPtrRef(pi.builtinType)) {
      assertx(inst->src(srcNum)->type() <= TPtrToGen);
      args.addr(srcLoc(env, inst, srcNum).reg(), TVOFF(m_data));
    } else if (pi.nativeArg && !pi.builtinType && !callee->byRef(i)) {
      // This condition indicates a MixedTV (i.e., TypedValue-by-value) arg.
      args.typedValue(srcNum);
    } else {
      args.ssa(srcNum, pi.builtinType == KindOfDouble);
    }
  }

  auto dest = [&] () -> CallDest {
    if (isBuiltinByRef(funcReturnType)) {
      if (!returnByValue) return kVoidDest; // indirect return
      return funcReturnType
        ? callDest(dstData) // String, Array, or Object
        : callDest(dstData, dstType); // Variant
    }
    return funcReturnType == KindOfDouble
      ? callDestDbl(env, inst)
      : callDest(env, inst);
  }();

  cgCallHelper(v, env, CallSpec::direct(callee->nativeFuncPtr()),
               dest, SyncOptions::Sync, args);

  // For primitive return types (int, bool, double) and returnByValue, the
  // return value is already in dstData/dstType.
  if (returnType.isSimpleType() || returnByValue) return;

  // For return by reference (String, Object, Array, Variant), the builtin
  // writes the return value into MInstrState::tvBuiltinReturn, from where it
  // has to be tested and copied.

  if (returnType.isReferenceType()) {
    // The return type is String, Array, or Object; fold nullptr to KindOfNull.
    assertx(isBuiltinByRef(funcReturnType) && isReqPtrRef(funcReturnType));

    v << load{rvmtl()[returnOffset], dstData};

    if (dstType.isValid()) {
      auto const sf = v.makeReg();
      auto const rtype = v.cns(returnType.toDataType());
      auto const nulltype = v.cns(KindOfNull);
      v << testq{dstData, dstData, sf};
      v << cmovb{CC_Z, sf, rtype, nulltype, dstType};
    }
    return;
  }

  if (returnType <= TCell || returnType <= TBoxedCell) {
    // The return type is Variant; fold KindOfUninit to KindOfNull.
    assertx(isBuiltinByRef(funcReturnType) && !isReqPtrRef(funcReturnType));
    static_assert(KindOfUninit == 0, "KindOfUninit must be 0 for test");

    v << load{rvmtl()[returnOffset + TVOFF(m_data)], dstData};

    if (dstType.isValid()) {
      auto const rtype = v.makeReg();
      v << loadb{rvmtl()[returnOffset + TVOFF(m_type)], rtype};

      auto const sf = v.makeReg();
      auto const nulltype = v.cns(KindOfNull);
      v << testb{rtype, rtype, sf};
      v << cmovb{CC_Z, sf, rtype, nulltype, dstType};
    }
    return;
  }

  not_reached();
}
예제 #23
0
파일: update.cpp 프로젝트: buchenberg/zorba
bool InsertIterator::nextImpl(store::Item_t& result, PlanState& aPlanState) const
{
  store::StoreConsts::NodeKind targetKind;
  bool elemParent;
  bool elemTarget;
  store::Item_t parent;
  store::Item_t target;
  store::Item_t source;
  std::vector<store::Item_t> attrs(16);
  std::vector<store::Item_t> nodes(16);
  ulong numAttrs = 0;
  ulong numNodes = 0;
  std::unique_ptr<store::PUL> pul;
  store::Item_t temp;

  store::CopyMode lCopyMode;
  bool typePreserve;
  bool nsPreserve;
  bool nsInherit;

  PlanIteratorState* state;
  DEFAULT_STACK_INIT(PlanIteratorState, state, aPlanState);

  typePreserve = (theSctx->construction_mode() == StaticContextConsts::cons_preserve ?
                  true : false);
  nsPreserve = theSctx->preserve_ns();
  nsInherit = theSctx->inherit_ns();

  lCopyMode.set(theDoCopy, typePreserve, nsPreserve, nsInherit);
  
  if (!consumeNext(target, theChild1, aPlanState))
    throw XQUERY_EXCEPTION( err::XUDY0027, ERROR_LOC( loc ) );

  if (theType == store::UpdateConsts::BEFORE ||
      theType == store::UpdateConsts::AFTER)
  {
    if (!target->isNode() ||
        target->getNodeKind() == store::StoreConsts::attributeNode ||
        target->getNodeKind() == store::StoreConsts::documentNode)
      throw XQUERY_EXCEPTION( err::XUTY0006, ERROR_LOC( loc ) );

    if (consumeNext(temp, theChild1, aPlanState))
      throw XQUERY_EXCEPTION( err::XUTY0006, ERROR_LOC( loc ) );

    if (target->getParent() == NULL)
      throw XQUERY_EXCEPTION( err::XUDY0029, ERROR_LOC( loc ) );

    parent = target->getParent();

    elemParent = (parent->getNodeKind() == store::StoreConsts::elementNode);

    // Do not preserve the type of the source nodes (we do this here so that
    // we don't have to use the upd::setToUntyped() primitive later, during
    // the application of the PUL).
    if (lCopyMode.theTypePreserve &&
        (!elemParent ||
         parent->getType()->equals(GENV_TYPESYSTEM.XS_UNTYPED_QNAME)))
      lCopyMode.theTypePreserve = false;

    while (consumeNext(source, theChild0, aPlanState))
    {
      ZORBA_FATAL(source->isNode(), "");

      if (source->getNodeKind() == store::StoreConsts::attributeNode)
      {
        if (numNodes > 0)
          throw XQUERY_EXCEPTION( err::XUTY0004, ERROR_LOC( loc ) );

        if (!elemParent)
          throw XQUERY_EXCEPTION( err::XUDY0030, ERROR_LOC( loc ) );

        attrs[numAttrs++].transfer(source);
        if (numAttrs == attrs.size())
          attrs.resize(2 * numAttrs);
      }
      else
      {
        nodes[numNodes++].transfer(source);
        if (numNodes == nodes.size())
          nodes.resize(2 * numNodes);
      }
    }

    areNodeModifiersViolated(theSctx, target, loc);

    pul.reset(GENV_ITEMFACTORY->createPendingUpdateList());

    if (numAttrs > 0)
    {
      attrs.resize(numAttrs);

      for (ulong i = 0; i < numAttrs; ++i)
        attrs[i] = attrs[i]->copy(NULL, lCopyMode);

      pul->addInsertAttributes(&loc, parent, attrs);
    }

    if (numNodes > 0)
    {
      nodes.resize(numNodes);

      for (ulong i = 0; i < numNodes; ++i)
        nodes[i] = nodes[i]->copy(NULL, lCopyMode);

      if (theType == store::UpdateConsts::BEFORE)
        pul->addInsertBefore(&loc, target, nodes);
      else
        pul->addInsertAfter(&loc, target, nodes);
    }

    result = pul.release();
    STACK_PUSH(result != NULL, state);
  }
  else
  {
    if (!target->isNode())
      throw XQUERY_EXCEPTION( err::XUTY0005, ERROR_LOC( loc ) );

    targetKind = target->getNodeKind();

    if (targetKind != store::StoreConsts::documentNode &&
        targetKind != store::StoreConsts::elementNode)
      throw XQUERY_EXCEPTION( err::XUTY0005, ERROR_LOC( loc ) );

    if (consumeNext(temp, theChild1, aPlanState))
      throw XQUERY_EXCEPTION( err::XUTY0005, ERROR_LOC( loc ) );

    elemTarget = (targetKind == store::StoreConsts::elementNode);

    if (lCopyMode.theTypePreserve &&
        (!elemTarget ||
         target->getType()->equals(GENV_TYPESYSTEM.XS_UNTYPED_QNAME)))
      lCopyMode.theTypePreserve = false;

    while (consumeNext(source, theChild0, aPlanState))
    {
      ZORBA_FATAL(source->isNode(), "");

      if (source->getNodeKind() == store::StoreConsts::attributeNode)
      {
        if (numNodes > 0)
          throw XQUERY_EXCEPTION( err::XUTY0004, ERROR_LOC( loc ) );

        if (!elemTarget)
          throw XQUERY_EXCEPTION( err::XUTY0022, ERROR_LOC( loc ) );

        attrs[numAttrs++].transfer(source);
        if (numAttrs == attrs.size())
          attrs.resize(2 * numAttrs);
      }
      else
      {
        nodes[numNodes++].transfer(source);
        if (numNodes == nodes.size())
          nodes.resize(2 * numNodes);
      }
    }

    areNodeModifiersViolated(theSctx, target, loc);

    pul.reset(GENV_ITEMFACTORY->createPendingUpdateList());

    if (numAttrs > 0)
    {
      attrs.resize(numAttrs);

      for (ulong i = 0; i < numAttrs; ++i)
        attrs[i] = attrs[i]->copy(NULL, lCopyMode);

      pul->addInsertAttributes(&loc, target, attrs);
    }

    if (numNodes > 0)
    {
      nodes.resize(numNodes);

      for (ulong i = 0; i < numNodes; ++i)
        nodes[i] = nodes[i]->copy(NULL, lCopyMode);

      if (theType == store::UpdateConsts::INTO)
        pul->addInsertInto(&loc, target, nodes);
      else if (theType == store::UpdateConsts::AS_FIRST_INTO)
        pul->addInsertFirst(&loc, target, nodes);
      else
        pul->addInsertLast(&loc, target, nodes);
    }

    result = pul.release();
    STACK_PUSH(result != NULL, state);
  }

  STACK_END (state);
}
예제 #24
0
void init() {
  if (g_initFlag.load(std::memory_order_acquire)) return;

  Lock l(s_initLock);
  if (g_initFlag.load(std::memory_order_acquire)) return;

  // Stop profiling before attempting to acquire the instance-counts lock. The
  // reason for having two flags is because ReadWriteLock can in certain
  // implementations favor readers over writers. Thus if there's a steady stream
  // of calls to profile(), we'll block indefinitely waiting to acquire the
  // instance-counts lock. Since this function is called from JITing threads,
  // this can eventually lead to starvation. So, set this flag to stop other
  // threads from attempting to acquire the instance-counts lock, and avoid
  // starvation.
  g_profileDoneFlag.store(true, std::memory_order_release);

  if (!RuntimeOption::RepoAuthoritative) {
    g_initFlag.store(true, std::memory_order_release);
    return;
  }
  if (do_assert) s_initThread.store(pthread_self(), std::memory_order_release);

  // First, grab a write lock on s_instanceCounts and grab the current set of
  // counts as quickly as possible to minimize blocking other threads still
  // trying to profile instance checks.
  typedef std::pair<const StringData*, unsigned> Count;
  std::vector<Count> counts;
  uint64_t total = 0;
  {
    // If you think of the read-write lock as a shared-exclusive lock instead,
    // the fact that we're grabbing a write lock to iterate over the table
    // makes more sense: it's safe to concurrently modify a
    // tbb::concurrent_hash_map, but iteration is not guaranteed to be safe
    // with concurrent insertions.
    WriteLock l(s_instanceCountsLock);
    for (auto& pair : s_instanceCounts) {
      counts.push_back(pair);
      total += pair.second;
    }
  }
  std::sort(counts.begin(), counts.end(), [&](const Count& a, const Count& b) {
    return a.second > b.second;
  });

  // Next, initialize s_instanceBitsMap with the top 127 most checked
  // classes. Bit 0 is reserved as an 'initialized' flag
  unsigned i = 1;
  uint64_t accum = 0;
  for (auto& item : counts) {
    if (i >= kNumInstanceBits) break;
    auto const cls = Unit::lookupUniqueClassInContext(item.first, nullptr);
    if (cls) {
      assertx(cls->attrs() & AttrUnique);
      s_instanceBitsMap[item.first] = i;
      accum += item.second;
      ++i;
    }
  }

  // Print out stats about what we ended up using
  if (Trace::moduleEnabledRelease(Trace::instancebits, 1)) {
    Trace::traceRelease("%s: %u classes, %" PRIu64 " (%.2f%%) of warmup"
                        " checks\n",
                        __FUNCTION__, i-1, accum, 100.0 * accum / total);
    if (Trace::moduleEnabledRelease(Trace::instancebits, 2)) {
      accum = 0;
      i = 1;
      for (auto& pair : counts) {
        if (i >= 256) {
          Trace::traceRelease("skipping the remainder of the %zu classes\n",
                              counts.size());
          break;
        }
        accum += pair.second;
        Trace::traceRelease("%3u %5.2f%% %7u -- %6.2f%% %7" PRIu64 " %s\n",
                            i++, 100.0 * pair.second / total, pair.second,
                            100.0 * accum / total, accum,
                            pair.first->data());
      }
    }
  }

  // Finally, update m_instanceBits on every Class that currently exists. This
  // must be done while holding a lock that blocks insertion of new Classes
  // into their class lists, but in practice most Classes will already be
  // created by now and this process is very fast.
  WriteLock clsLocker(g_clsInitLock);
  NamedEntity::foreach_class([&](Class* cls) {
    cls->setInstanceBitsAndParents();
  });

  if (do_assert) {
    // There isn't a canonical invalid pthread_t, but this is only used for the
    // assert in lookup() and it's ok to have false negatives.
    s_initThread.store(pthread_t{}, std::memory_order_release);
  }
  g_initFlag.store(true, std::memory_order_release);
}
예제 #25
0
void cgCall(IRLS& env, const IRInstruction* inst) {
  auto const sp = srcLoc(env, inst, 0).reg();
  auto const fp = srcLoc(env, inst, 1).reg();
  auto const extra = inst->extra<Call>();
  auto const callee = extra->callee;
  auto const argc = extra->numParams;

  auto& v = vmain(env);
  auto& vc = vcold(env);
  auto const catchBlock = label(env, inst->taken());

  auto const calleeSP = sp[cellsToBytes(extra->spOffset.offset)];
  auto const calleeAR = calleeSP + cellsToBytes(argc);

  v << store{fp, calleeAR + AROFF(m_sfp)};
  v << storeli{safe_cast<int32_t>(extra->after), calleeAR + AROFF(m_soff)};

  if (extra->fcallAwait) {
    // This clobbers any flags that might have already been set on the callee
    // AR (e.g., by SpillFrame), but this is okay because there should never be
    // any conflicts; see the documentation in act-rec.h.
    auto const imm = static_cast<int32_t>(
      ActRec::encodeNumArgsAndFlags(argc, ActRec::Flags::IsFCallAwait)
    );
    v << storeli{imm, calleeAR + AROFF(m_numArgsAndFlags)};
  }

  auto const isNativeImplCall = callee &&
                                callee->builtinFuncPtr() &&
                                !callee->nativeFuncPtr() &&
                                argc == callee->numParams();
  if (isNativeImplCall) {
    // The assumption here is that for builtins, the generated func contains
    // only a single opcode (NativeImpl), and there are no non-argument locals.
    if (do_assert) {
      assertx(argc == callee->numLocals());
      assertx(callee->numIterators() == 0);

      auto addr = callee->getEntry();
      while (peek_op(addr) == Op::AssertRATL) {
        addr += instrLen(addr);
      }
      assertx(peek_op(addr) == Op::NativeImpl);
      assertx(addr + instrLen(addr) ==
              callee->unit()->entry() + callee->past());
    }

    v << store{v.cns(mcg->ustubs().retHelper), calleeAR + AROFF(m_savedRip)};
    if (callee->attrs() & AttrMayUseVV) {
      v << storeqi{0, calleeAR + AROFF(m_invName)};
    }
    v << lea{calleeAR, rvmfp()};

    emitCheckSurpriseFlagsEnter(v, vc, fp, Fixup(0, argc), catchBlock);

    auto const builtinFuncPtr = callee->builtinFuncPtr();
    TRACE(2, "Calling builtin preClass %p func %p\n",
          callee->preClass(), builtinFuncPtr);

    // We sometimes call this while curFunc() isn't really the builtin, so make
    // sure to record the sync point as if we are inside the builtin.
    if (FixupMap::eagerRecord(callee)) {
      auto const syncSP = v.makeReg();
      v << lea{calleeSP, syncSP};
      emitEagerSyncPoint(v, callee->getEntry(), rvmtl(), rvmfp(), syncSP);
    }

    // Call the native implementation.  This will free the locals for us in the
    // normal case.  In the case where an exception is thrown, the VM unwinder
    // will handle it for us.
    auto const done = v.makeBlock();
    v << vinvoke{CallSpec::direct(builtinFuncPtr), v.makeVcallArgs({{rvmfp()}}),
                 v.makeTuple({}), {done, catchBlock}, Fixup(0, argc)};
    env.catch_calls[inst->taken()] = CatchCall::CPP;

    v = done;
    // The native implementation already put the return value on the stack for
    // us, and handled cleaning up the arguments.  We have to update the frame
    // pointer and the stack pointer, and load the return value into the return
    // register so the trace we are returning to has it where it expects.
    // TODO(#1273094): We should probably modify the actual builtins to return
    // values via registers using the C ABI and do a reg-to-reg move.
    loadTV(v, inst->dst(), dstLoc(env, inst, 0), rvmfp()[AROFF(m_r)], true);
    v << load{rvmfp()[AROFF(m_sfp)], rvmfp()};
    emitRB(v, Trace::RBTypeFuncExit, callee->fullName()->data());
    return;
  }

  v << lea{calleeAR, rvmfp()};

  if (RuntimeOption::EvalHHIRGenerateAsserts) {
    v << syncvmsp{v.cns(0x42)};

    constexpr uint64_t kUninitializedRIP = 0xba5eba11acc01ade;
    emitImmStoreq(v, kUninitializedRIP, rvmfp()[AROFF(m_savedRip)]);
  }

  // Emit a smashable call that initially calls a recyclable service request
  // stub.  The stub and the eventual targets take rvmfp() as an argument,
  // pointing to the callee ActRec.
  auto const target = callee
    ? mcg->ustubs().immutableBindCallStub
    : mcg->ustubs().bindCallStub;

  auto const done = v.makeBlock();
  v << callphp{target, php_call_regs(), {{done, catchBlock}}};
  env.catch_calls[inst->taken()] = CatchCall::PHP;
  v = done;

  auto const dst = dstLoc(env, inst, 0);
  v << defvmret{dst.reg(0), dst.reg(1)};
}
예제 #26
0
/*
 * Command line options for autostart (keep synchronized with binaries/system/readme.txt):
 *
 * -autostart="TYPEDIR/MAPNAME"         enables autostart and sets MAPNAME; TYPEDIR is skirmishes, scenarios, or random
 * -autostart-ai=PLAYER:AI              sets the AI for PLAYER (e.g. 2:petra)
 * -autostart-aidiff=PLAYER:DIFF        sets the DIFFiculty of PLAYER's AI (0: sandbox, 5: very hard)
 * -autostart-civ=PLAYER:CIV            sets PLAYER's civilisation to CIV (skirmish and random maps only)
 * -autostart-aiseed=AISEED             sets the seed used for the AI random generator (default 0, use -1 for random)
 * Multiplayer:
 * -autostart-playername=NAME		sets local player NAME (default 'anonymous')
 * -autostart-host                      sets multiplayer host mode
 * -autostart-host-players=NUMBER       sets NUMBER of human players for multiplayer game (default 2)
 * -autostart-client=IP                 sets multiplayer client to join host at given IP address
 * Random maps only:
 * -autostart-seed=SEED                 sets random map SEED value (default 0, use -1 for random)
 * -autostart-size=TILES                sets random map size in TILES (default 192)
 * -autostart-players=NUMBER            sets NUMBER of players on random map (default 2)
 *
 * Examples:
 * 1) "Bob" will host a 2 player game on the Arcadia map:
 * -autostart="scenarios/Arcadia 02" -autostart-host -autostart-host-players=2 -autostart-playername="Bob"
 * 2) Load Alpine Lakes random map with random seed, 2 players (Athens and Britons), and player 2 is PetraBot:
 * -autostart="random/alpine_lakes" -autostart-seed=-1 -autostart-players=2 -autostart-civ=1:athen -autostart-civ=2:brit -autostart-ai=2:petra
*/
bool Autostart(const CmdLineArgs& args)
{
	CStr autoStartName = args.Get("autostart");

	if (autoStartName.empty())
		return false;

	g_Game = new CGame();

	ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
	JSContext* cx = scriptInterface.GetContext();
	JSAutoRequest rq(cx);

	JS::RootedValue attrs(cx);
	scriptInterface.Eval("({})", &attrs);
	JS::RootedValue settings(cx);
	scriptInterface.Eval("({})", &settings);
	JS::RootedValue playerData(cx);
	scriptInterface.Eval("([])", &playerData);

	// The directory in front of the actual map name indicates which type
	// of map is being loaded. Drawback of this approach is the association
	// of map types and folders is hard-coded, but benefits are:
	// - No need to pass the map type via command line separately
	// - Prevents mixing up of scenarios and skirmish maps to some degree
	Path mapPath = Path(autoStartName);
	std::wstring mapDirectory = mapPath.Parent().Filename().string();
	std::string mapType;

	if (mapDirectory == L"random")
	{
		// Default seed is 0
		u32 seed = 0;
		CStr seedArg = args.Get("autostart-seed");

		if (!seedArg.empty())
		{
			// Random seed value
			if (seedArg == "-1")
				seed = rand();
			else
				seed = seedArg.ToULong();
		}
		
		// Random map definition will be loaded from JSON file, so we need to parse it
		std::wstring scriptPath = L"maps/" + autoStartName.FromUTF8() + L".json";
		JS::RootedValue scriptData(cx);
		scriptInterface.ReadJSONFile(scriptPath, &scriptData);
		if (!scriptData.isUndefined() && scriptInterface.GetProperty(scriptData, "settings", &settings))
		{
			// JSON loaded ok - copy script name over to game attributes
			std::wstring scriptFile;
			scriptInterface.GetProperty(settings, "Script", scriptFile);
			scriptInterface.SetProperty(attrs, "script", scriptFile);				// RMS filename
		}
		else
		{
			// Problem with JSON file
			LOGERROR("Autostart: Error reading random map script '%s'", utf8_from_wstring(scriptPath));
			throw PSERROR_Game_World_MapLoadFailed("Error reading random map script.\nCheck application log for details.");
		}

		// Get optional map size argument (default 192)
		uint mapSize = 192;
		if (args.Has("autostart-size"))
		{
			CStr size = args.Get("autostart-size");
			mapSize = size.ToUInt();
		}

		scriptInterface.SetProperty(settings, "Seed", seed);		// Random seed
		scriptInterface.SetProperty(settings, "Size", mapSize);		// Random map size (in patches)

		// Get optional number of players (default 2)
		size_t numPlayers = 2;
		if (args.Has("autostart-players"))
		{
			CStr num = args.Get("autostart-players");
			numPlayers = num.ToUInt();
		}

		// Set up player data
		for (size_t i = 0; i < numPlayers; ++i)
		{
			JS::RootedValue player(cx);
			scriptInterface.Eval("({})", &player);

			// We could load player_defaults.json here, but that would complicate the logic
			// even more and autostart is only intended for developers anyway
			scriptInterface.SetProperty(player, "Civ", std::string("athen"));
			scriptInterface.SetPropertyInt(playerData, i, player);
		}
		mapType = "random";
	}
	else if (mapDirectory == L"scenarios" || mapDirectory == L"skirmishes")
	{
		// Initialize general settings from the map data so some values
		// (e.g. name of map) are always present, even when autostart is
		// partially configured
		CStr8 mapSettingsJSON = LoadSettingsOfScenarioMap("maps/" + autoStartName + ".xml");
		scriptInterface.ParseJSON(mapSettingsJSON, &settings);
		
		// Initialize the playerData array being modified by autostart
		// with the real map data, so sensible values are present:
		scriptInterface.GetProperty(settings, "PlayerData", &playerData);

		if (mapDirectory == L"scenarios")
			mapType = "scenario";
		else
			mapType = "skirmish";
	}
	else
	{
		LOGERROR("Autostart: Unrecognized map type '%s'", utf8_from_wstring(mapDirectory));
		throw PSERROR_Game_World_MapLoadFailed("Unrecognized map type.\nConsult readme.txt for the currently supported types.");
	}
	scriptInterface.SetProperty(attrs, "mapType", mapType);
	scriptInterface.SetProperty(attrs, "map", std::string("maps/" + autoStartName));
	scriptInterface.SetProperty(settings, "mapType", mapType);

	// Set seed for AIs
	u32 aiseed = 0;
	if (args.Has("autostart-aiseed"))
	{
		CStr seedArg = args.Get("autostart-aiseed");
		if (seedArg == "-1")
			aiseed = rand();
		else
			aiseed = seedArg.ToULong();
	}
	scriptInterface.SetProperty(settings, "AISeed", aiseed);

	// Set player data for AIs
	//		attrs.settings = { PlayerData: [ { AI: ... }, ... ] }:
	if (args.Has("autostart-ai"))
	{
		std::vector<CStr> aiArgs = args.GetMultiple("autostart-ai");
		for (size_t i = 0; i < aiArgs.size(); ++i)
		{
			int playerID = aiArgs[i].BeforeFirst(":").ToInt();

			// Instead of overwriting existing player data, modify the array
			JS::RootedValue player(cx);
			if (!scriptInterface.GetPropertyInt(playerData, playerID-1, &player) || player.isUndefined())
			{
				if (mapDirectory == L"scenarios" || mapDirectory == L"skirmishes")
				{
					// playerID is certainly bigger than this map player number
					LOGWARNING("Autostart: Invalid player %d in autostart-ai option", playerID);
					continue;
				}
				scriptInterface.Eval("({})", &player);
			}

			CStr name = aiArgs[i].AfterFirst(":");
			scriptInterface.SetProperty(player, "AI", std::string(name));
			scriptInterface.SetProperty(player, "AIDiff", 3);
			scriptInterface.SetPropertyInt(playerData, playerID-1, player);
		}
	}
	// Set AI difficulty
	if (args.Has("autostart-aidiff"))
	{
		std::vector<CStr> civArgs = args.GetMultiple("autostart-aidiff");
		for (size_t i = 0; i < civArgs.size(); ++i)
		{
			int playerID = civArgs[i].BeforeFirst(":").ToInt();

			// Instead of overwriting existing player data, modify the array
			JS::RootedValue player(cx);
			if (!scriptInterface.GetPropertyInt(playerData, playerID-1, &player) || player.isUndefined())
			{
				if (mapDirectory == L"scenarios" || mapDirectory == L"skirmishes")
				{
					// playerID is certainly bigger than this map player number
					LOGWARNING("Autostart: Invalid player %d in autostart-aidiff option", playerID);
					continue;
				}
				scriptInterface.Eval("({})", &player);
			}

			int difficulty = civArgs[i].AfterFirst(":").ToInt();			
			scriptInterface.SetProperty(player, "AIDiff", difficulty);
			scriptInterface.SetPropertyInt(playerData, playerID-1, player);
		}
	}
	// Set player data for Civs
	if (args.Has("autostart-civ"))
	{
		if (mapDirectory != L"scenarios")
		{
			std::vector<CStr> civArgs = args.GetMultiple("autostart-civ");
			for (size_t i = 0; i < civArgs.size(); ++i)
			{
				int playerID = civArgs[i].BeforeFirst(":").ToInt();

				// Instead of overwriting existing player data, modify the array
				JS::RootedValue player(cx);
				if (!scriptInterface.GetPropertyInt(playerData, playerID-1, &player) || player.isUndefined())
				{
					if (mapDirectory == L"skirmishes")
					{
						// playerID is certainly bigger than this map player number
						LOGWARNING("Autostart: Invalid player %d in autostart-civ option", playerID);
						continue;
					}
					scriptInterface.Eval("({})", &player);
				}
			
				CStr name = civArgs[i].AfterFirst(":");			
				scriptInterface.SetProperty(player, "Civ", std::string(name));
				scriptInterface.SetPropertyInt(playerData, playerID-1, player);
			}
		}
		else
			LOGWARNING("Autostart: Option 'autostart-civ' is invalid for scenarios");
	}

	// Add player data to map settings
	scriptInterface.SetProperty(settings, "PlayerData", playerData);

	// Add map settings to game attributes
	scriptInterface.SetProperty(attrs, "settings", settings);

	JS::RootedValue mpInitData(cx);
	scriptInterface.Eval("({isNetworked:true, playerAssignments:{}})", &mpInitData);
	scriptInterface.SetProperty(mpInitData, "attribs", attrs);

	// Get optional playername
	CStrW userName = L"anonymous";
	if (args.Has("autostart-playername"))
	{
		userName = args.Get("autostart-playername").FromUTF8();
	}

	if (args.Has("autostart-host"))
	{
		InitPs(true, L"page_loading.xml", &scriptInterface, mpInitData);

		size_t maxPlayers = 2;
		if (args.Has("autostart-host-players"))
			maxPlayers = args.Get("autostart-host-players").ToUInt();

		g_NetServer = new CNetServer(maxPlayers);

		g_NetServer->UpdateGameAttributes(&attrs, scriptInterface);

		bool ok = g_NetServer->SetupConnection();
		ENSURE(ok);

		g_NetClient = new CNetClient(g_Game);
		g_NetClient->SetUserName(userName);
		g_NetClient->SetupConnection("127.0.0.1");
	}
	else if (args.Has("autostart-client"))
	{
		InitPs(true, L"page_loading.xml", &scriptInterface, mpInitData);

		g_NetClient = new CNetClient(g_Game);
		g_NetClient->SetUserName(userName);

		CStr ip = args.Get("autostart-client");
		if (ip.empty())
			ip = "127.0.0.1";

		bool ok = g_NetClient->SetupConnection(ip);
		ENSURE(ok);
	}
	else
	{
		g_Game->SetPlayerID(1);
		g_Game->StartGame(&attrs, "");

		LDR_NonprogressiveLoad();

		PSRETURN ret = g_Game->ReallyStartGame();
		ENSURE(ret == PSRETURN_OK);

		InitPs(true, L"page_session.xml", NULL, JS::UndefinedHandleValue);
	}

	return true;
}
예제 #27
0
int
runTests(
			int		argc,
			char*	argv[])
{
	// Just hoist everything...
	XALAN_CPP_NAMESPACE_USE

	MemoryManagerType& theManager = XalanMemMgrs::getDefaultXercesMemMgr();

	XalanFileUtility	h(theManager);

	// Set the program help string,  then get the command line parameters.
	//
	setHelp(h);

	bool setGold = false;

	const XalanDOMString	processorType(XALAN_STATIC_UCODE_STRING("XalanC"));

	if (h.getParams(argc, argv, "PERFT-RESULTS", setGold) == true)
	{
		XalanTransformer xalan;

		// Generate Unique Run id and processor info
		XalanDOMString UniqRunid;
		h.generateUniqRunid(UniqRunid);


		// Defined basic constants for file manipulation and open results file
		const XalanDOMString  resultFilePrefix("cpp");
		XalanDOMString  resultsFile= h.args.output;
		resultsFile += resultFilePrefix;
		resultsFile += UniqRunid;
		resultsFile += XalanFileUtility::s_xmlSuffix;


		XalanXMLFileReporter	logFile(theManager, resultsFile);
		logFile.logTestFileInit("Performance Testing - Reports various performance metrics using the Transformer");

		// Get the list of sub-directories below "base" and iterate through them
		bool foundDir = false;		// Flag indicates directory found. Used in conjunction with -sub cmd-line arg.

		typedef XalanFileUtility::FileNameVectorType		FileNameVectorType;

		FileNameVectorType dirs;
		h.getDirectoryNames(h.args.base, dirs);

		for(FileNameVectorType::size_type	j = 0; j < dirs.size(); j++)
		{
			// Run specific category of files from given directory
			if (length(h.args.sub) > 0 && !equals(dirs[j], h.args.sub))
			{
				continue;
			}

			cout << "Processing files in Directory: " << dirs[j] << endl;

			// Check that output directory is there.
			XalanDOMString  theOutputDir = h.args.output;
			theOutputDir += dirs[j];
			h.checkAndCreateDir(theOutputDir);

					
			// Indicate that directory was processed and get test files from the directory
			foundDir = true;
			FileNameVectorType files;
			h.getTestFileNames(h.args.base, dirs[j], false, files);
			XalanDOMString logEntry;
			logEntry = "Performance Directory: ";
			logEntry += dirs[j];
			logFile.logTestCaseInit(logEntry);

			const long	iterCount = h.args.iters;

			for(FileNameVectorType::size_type i = 0; i < files.size(); i++)
			{
				// Define  variables used for timing and reporting ...
				clock_t startTime, endTime, accmTime, avgEtoe;
				double timeinMilliseconds = 0, theAverage =0;
				int transformResult = 0;

				typedef XalanXMLFileReporter::Hashtable	Hashtable;

				Hashtable attrs(theManager);

				attrs.insert(Hashtable::value_type(XalanDOMString("idref"), files[i]));
				attrs.insert(Hashtable::value_type(XalanDOMString("UniqRunid"),UniqRunid));
				attrs.insert(Hashtable::value_type(XalanDOMString("processor"),processorType));
				logFile.addMetricToAttrs("Iterations",iterCount, attrs);
								
				if (h.args.skip)
				{
					if (checkForExclusion(files[i]))
						continue;
				}

				XalanDOMString  theXSLFile = h.args.base;
				theXSLFile += dirs[j];
				theXSLFile += XalanFileUtility::s_pathSep;
				theXSLFile += files[i];

				XalanDOMString  theXMLFile; 
				h.generateFileName(theXSLFile,"xml", theXMLFile);

				XalanDOMString  outbase = h.args.output;
				outbase += dirs[j];
				outbase += XalanFileUtility::s_pathSep;
				outbase += files[i]; 
				XalanDOMString  theOutputFile;
				h.generateFileName(outbase, "out", theOutputFile);

				const XSLTInputSource	xslInputSource(theXSLFile);
				const XSLTInputSource	xmlInputSource(theXMLFile);
				const XSLTResultTarget	theResultTarget(theOutputFile);

				attrs.insert(Hashtable::value_type(XalanDOMString("href"), theXSLFile));
				cout << endl << files[i] << endl;

				// Time the parsing(compile) of the XSL stylesheet and report the results..
				//
				startTime = clock();
				const XalanCompiledStylesheet*	compiledSS = 0;
				xalan.compileStylesheet(xslInputSource, compiledSS);
				endTime = clock();

				if (compiledSS == 0)
				{
					continue;
				}

				timeinMilliseconds = calculateElapsedTime(startTime, endTime);
				cout << "   XSL: " << timeinMilliseconds << " milliseconds, Parse" << endl;
				logFile.addMetricToAttrs("parsexsl",timeinMilliseconds, attrs);	

				// Time the parsing of the input XML and report the results..
				//
				startTime = clock();
				const XalanParsedSource*	parsedSource = 0;
				xalan.parseSource(xmlInputSource, parsedSource);
				endTime = clock();

				if (parsedSource == 0)
				{
					continue;
				}

				timeinMilliseconds = calculateElapsedTime(startTime, endTime);
				cout << "   XML: " << timeinMilliseconds << " milliseconds, Parse" <<endl;
				logFile.addMetricToAttrs("parsexml",timeinMilliseconds, attrs);

				// Perform One transform using parsed stylesheet and unparsed xml source, report results...
				// 
				startTime = clock();
					transformResult = xalan.transform(xmlInputSource, compiledSS, theResultTarget);
				endTime = clock();
				if(!transformResult)
				{
					timeinMilliseconds = calculateElapsedTime(startTime, endTime);
					cout << endl << "   One: " << timeinMilliseconds << " w/Parsed XSL." << endl;
					logFile.addMetricToAttrs("single", timeinMilliseconds, attrs);	
				}
				else
				{
					cout << xalan.getLastError();
					return -1;
				}

				// Do One eTOe transform with no pre parsing of either xsl or xml files.
				// And output metrics to console and result log
				startTime = clock();
					transformResult = xalan.transform(xmlInputSource, xslInputSource, theResultTarget);
				endTime = clock();
				if(!transformResult)
				{
					timeinMilliseconds = calculateElapsedTime(startTime, endTime);
					cout << "   One: " << timeinMilliseconds << " eTOe." << endl;
					logFile.addMetricToAttrs("etoe", timeinMilliseconds, attrs);	
				}
				else
				{
					cout << xalan.getLastError();
					return -1;
				}


				// Perform multiple transforms and calculate the average time ..
				// These are done 3 different ways.
				//
				// FIRST: Parsed XSL Stylesheet and Parsed XML Source.
				//
				accmTime = 0;
				for(int j = 0; j < iterCount; ++j)
				{	
					startTime = clock();
						transformResult = xalan.transform(*parsedSource, compiledSS, theResultTarget);
					endTime = clock();
					
					accmTime += endTime - startTime;
				}

				theAverage = calculateAvgTime(accmTime, iterCount); 
				cout << endl << "   Avg: " << theAverage << " for " << iterCount << " iter's w/Parsed files" << endl;
				logFile.addMetricToAttrs("avgparsedxml",theAverage, attrs);
				

				// SECOND: Parsed Stylesheet and UnParsed XML Source.
				// This is currently how the XalanJ 2.0 is performing transforms
				//
				accmTime = 0;
				for(int k = 0; k < iterCount; ++k)
				{
					startTime = clock();
						transformResult = xalan.transform(xmlInputSource, compiledSS, theResultTarget);
					endTime = clock();
					
					accmTime += endTime - startTime;						
				}
				theAverage = calculateAvgTime(accmTime, iterCount);
				cout << "   Avg: " << theAverage << " for " << iterCount << " iter's w/UnParsed XML" << endl;
				logFile.addMetricToAttrs("avgunparsedxml",theAverage, attrs);


				// THIRD: Neither Stylesheet nor XML Source are parsed.
				// Perform multiple etoe transforms and calculate the average ...
				//
				avgEtoe = 0;
				for(int jj = 0; jj < iterCount; ++jj)
				{	
					startTime = clock();
						transformResult = xalan.transform(xmlInputSource, xslInputSource, theResultTarget);
					endTime = clock();
					
					avgEtoe += endTime - startTime;						
				}
				theAverage = calculateAvgTime(avgEtoe,iterCount);

				// Output average transform time to console and result log
				cout << "   Avg: " << theAverage << " for " << iterCount << " iter's of eToe" << endl;
				logFile.addMetricToAttrs("avgetoe",theAverage, attrs);

				logFile.logElementWAttrs(10, "perf", attrs, "xxx");

				xalan.destroyParsedSource(parsedSource);
				xalan.destroyStylesheet(compiledSS);

			}

			logEntry = "Performance Directory: ";
			logEntry += dirs[j];
 			logFile.logTestCaseClose(logEntry, XalanDOMString("Done"));
		}

		// Check to see if -sub cmd-line directory was processed correctly.
		if (!foundDir)
		{
			cout << "Specified test directory: \"" << c_str(TranscodeToLocalCodePage(h.args.sub)) << "\" not found" << endl;
		}

		h.reportPassFail(logFile, UniqRunid);
		logFile.logTestFileClose("Performance", "Done");
		logFile.close();
	}

	return 0;
}
예제 #28
0
ScXmlStreamAttributes ScXmlStreamReader::scAttributes(void) const
{
	ScXmlStreamAttributes attrs(attributes());
	return attrs;
}
예제 #29
0
Object c_Closure::t_bindto(const Variant& newthis, const Variant& scope) {
  if (RuntimeOption::RepoAuthoritative &&
      RuntimeOption::EvalAllowScopeBinding) {
    raise_warning("Closure binding is not supported in RepoAuthoritative mode");
    return Object{};
  }

  auto const cls = getVMClass();
  auto const invoke = cls->getCachedInvoke();

  ObjectData* od = nullptr;
  if (newthis.isObject()) {
    if (invoke->isStatic()) {
      raise_warning("Cannot bind an instance to a static closure");
    } else {
      od = newthis.getObjectData();
    }
  } else if (!newthis.isNull()) {
    raise_warning("Closure::bindto() expects parameter 1 to be object");
    return Object{};
  }

  auto const curscope = invoke->cls();
  auto newscope = curscope;

  if (scope.isObject()) {
    newscope = scope.getObjectData()->getVMClass();
  } else if (scope.isString()) {
    auto const className = scope.getStringData();

    if (!className->equal(s_static.get())) {
      newscope = Unit::loadClass(className);
      if (!newscope) {
        raise_warning("Class '%s' not found", className->data());
        return Object{};
      }
    }
  } else if (scope.isNull()) {
    newscope = nullptr;
  } else {
    raise_warning("Closure::bindto() expects parameter 2 "
                  "to be string or object");
    return Object{};
  }

  if (od && !newscope) {
    // Bound closures should be scoped.  If no scope is specified, scope it to
    // the Closure class.
    newscope = static_cast<Class*>(c_Closure::classof());
  }

  bool thisNotOfCtx = od && !od->getVMClass()->classof(newscope);

  if (!RuntimeOption::EvalAllowScopeBinding) {
    if (newscope != curscope) {
      raise_warning("Re-binding closure scopes is disabled");
      return Object{};
    }

    if (thisNotOfCtx) {
      raise_warning("Binding to objects not subclassed from closure "
                    "context is disabled");
      return Object{};
    }
  }

  c_Closure* clone = Clone(this);
  clone->setClass(nullptr);

  Attr curattrs = invoke->attrs();
  Attr newattrs = static_cast<Attr>(curattrs & ~AttrHasForeignThis);

  if (od) {
    od->incRefCount();
    clone->setThis(od);

    if (thisNotOfCtx) {
      // If the bound $this is not a subclass of the context class, then we
      // have to pessimize translation.
      newattrs |= AttrHasForeignThis;
    }
  } else if (newscope) {
    // If we attach a scope to a function with no bound $this we need to make
    // the function static.
    newattrs |= AttrStatic;
    clone->setClass(newscope);
  }

  // If we are changing either the scope or the attributes of the closure, we
  // need to re-scope its Closure subclass.
  if (newscope != curscope || newattrs != curattrs) {
    assert(newattrs != AttrNone);

    auto newcls = cls->rescope(newscope, newattrs);
    clone->setVMClass(newcls);
  }

  return Object(clone);
}
예제 #30
0
string conf_gen::gen_conf() {

	string spec_line = "# COMPUTE NODES";
	string ctlmachine_line = "ControlMachine=##";
	string ctladdr_line = "ControlAddr=##";

	bool spec_line_hit = false;

	string conf_line;
	ifstream ifs(_conf_file);

	while (getline(ifs, conf_line)) {

//		string line = replace_at_tok(conf_line);
		string line = conf_line;

		if (line == spec_line) { //"# COMPUTE NODES";

			spec_line_hit = true;
			_conf_list.push_back(line);

		} else if (line == ctlmachine_line) { //ControlMachine=##

			char buf[100];
			sprintf(buf, "ControlMachine=%s", _ctlmachine.c_str());

			string tmp(buf);
			_conf_list.push_back(tmp);

		} else if (line == ctladdr_line) { //ControlAddr=##

			char buf[100];
			sprintf(buf, "ControlAddr=%s", _ctladdr.c_str());

			string tmp(buf);
			_conf_list.push_back(tmp);
		} else {

			if (spec_line_hit) {

				_store_list.push_back(line);
				//spec_line_hit = false;

			} else {

				_conf_list.push_back(line);
			}
		}
	}

	/*NodeName=node-[3-4] Nodeaddr=node-[3-4].xiaobing.usrc CPUs=2 Sockets=2 CoresPerSocket=1 ThreadsPerCore=1 State=UNKNOWN*/
	for (IT it = _store_list.begin(); it != _store_list.end(); it++) {

		str_tok attrs(*it); // " ", delimiter

		bool nodes_hit = false;
		bool nodename_hit = false;
		bool nodeaddr_hit = false;

		string nodes = "Nodes"; //Nodes=node-[2-101]
		string nodename = "NodeName"; //NodeName=node-[2-101]
		string nodeaddr = "Nodeaddr"; //Nodeaddr=node-[3-4].xiaobing.usrc

		while (attrs.has_more_tokens()) {

			string attr = trim(attrs.next_token()); //Nodeaddr=node-[3-4].xiaobing.usrc

			str_tok name_value(attr, "=");
			string name = name_value.next_token(); //e.g. Nodeaddr

			if (name == nodes) { //"Nodes"
				nodes_hit = true;
			} else if (name == nodename) { //"NodeName"
				nodename_hit = true;
			} else if (name == nodeaddr) { //"Nodeaddr"
				nodeaddr_hit = true;
			} else
				;

			if (nodes_hit) {

				char buf[100];
				sprintf(buf, "Nodes=node-[%d-%d]", _start, _end);

				string tmp(buf);
				_spec_list.push_back(tmp);

				nodes_hit = false;

			} else if (nodename_hit) {

				char buf[100];
				sprintf(buf, "NodeName=node-[%d-%d]", _start, _end);
				string tmp(buf);
				_spec_list.push_back(tmp);

				nodename_hit = false;

			} else if (nodeaddr_hit) {

				string node_addr_list = gen_node_arr_list();

				char buf[10000];
				sprintf(buf, "Nodeaddr=%s", node_addr_list.c_str());
				string tmp(buf);
				_spec_list.push_back(tmp);

				nodeaddr_hit = false;

			} else {
				_spec_list.push_back(attr);
			}
		}

		_spec_list.push_back("\n");
	}

	return to_string();
}