1 /*
   2  * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 import java.io.File;
  26 import java.util.Enumeration;
  27 import java.util.Hashtable;
  28 import java.util.Iterator;
  29 import java.util.Vector;
  30 
  31 class BuildConfig {
  32     Hashtable vars;
  33     Vector basicNames, basicPaths;
  34     String[] context;
  35 
  36     static CompilerInterface ci;
  37     static CompilerInterface getCI() {
  38         if (ci == null) {
  39             String comp = (String)getField(null, "CompilerVersion");
  40             try {
  41                 ci = (CompilerInterface)Class.forName("CompilerInterface" + comp).newInstance();
  42             } catch (Exception cnfe) {
  43                 System.err.println("Cannot find support for compiler " + comp);
  44                 throw new RuntimeException(cnfe.toString());
  45             }
  46         }
  47         return ci;
  48     }
  49 
  50     protected void initNames(String flavour, String build, String outDll) {
  51         if (vars == null) vars = new Hashtable();
  52 
  53         String flavourBuild =  flavour + "_" + build;
  54         String platformName = getFieldString(null, "PlatformName");
  55         System.out.println();
  56         System.out.println(flavourBuild);
  57 
  58         put("Name", getCI().makeCfgName(flavourBuild, platformName));
  59         put("Flavour", flavour);
  60         put("Build", build);
  61         put("PlatformName", platformName);
  62 
  63         // ones mentioned above were needed to expand format
  64         String buildBase = expandFormat(getFieldString(null, "BuildBase"));
  65         String sourceBase = getFieldString(null, "SourceBase");
  66         String outDir = buildBase;
  67 
  68         put("Id", flavourBuild);
  69         put("OutputDir", outDir);
  70         put("SourceBase", sourceBase);
  71         put("BuildBase", buildBase);
  72         put("OutputDll", outDir + Util.sep + outDll);
  73 
  74         context = new String [] {flavourBuild, flavour, build, null};
  75     }
  76 
  77     protected void init(Vector includes, Vector defines) {
  78         initDefaultDefines(defines);
  79         initDefaultCompilerFlags(includes);
  80         initDefaultLinkerFlags();
  81         handleDB();
  82     }
  83 
  84 
  85     protected void initDefaultCompilerFlags(Vector includes) {
  86         Vector compilerFlags = new Vector();
  87 
  88         compilerFlags.addAll(getCI().getBaseCompilerFlags(getV("Define"),
  89                                                           includes,
  90                                                           get("OutputDir")));
  91 
  92         put("CompilerFlags", compilerFlags);
  93     }
  94 
  95     protected void initDefaultLinkerFlags() {
  96         Vector linkerFlags = new Vector();
  97 
  98         linkerFlags.addAll(getCI().getBaseLinkerFlags( get("OutputDir"), get("OutputDll"), get("PlatformName")));
  99 
 100         put("LinkerFlags", linkerFlags);
 101     }
 102 
 103     DirectoryTree getSourceTree(String sourceBase, String startAt) {
 104         DirectoryTree tree = new DirectoryTree();
 105 
 106         tree.addSubdirToIgnore("Codemgr_wsdata");
 107         tree.addSubdirToIgnore("deleted_files");
 108         tree.addSubdirToIgnore("SCCS");
 109         tree.setVerbose(true);
 110         if (startAt != null) {
 111             tree.readDirectory(sourceBase + File.separator + startAt);
 112         } else {
 113             tree.readDirectory(sourceBase);
 114         }
 115 
 116         return tree;
 117     }
 118 
 119 
 120     Vector getPreferredPaths() {
 121         Vector preferredPaths = new Vector();
 122 
 123         // In the case of multiple files with the same name in
 124         // different subdirectories, prefer these versions
 125         preferredPaths.add("windows");
 126         preferredPaths.add("x86");
 127         preferredPaths.add("closed");
 128 
 129         // Also prefer "opto" over "adlc" for adlcVMDeps.hpp
 130         preferredPaths.add("opto");
 131 
 132         return preferredPaths;
 133     }
 134 
 135 
 136     void handleDB() {
 137         WinGammaPlatform platform = (WinGammaPlatform)getField(null, "PlatformObject");
 138 
 139         putSpecificField("AllFilesHash", computeAllFiles(platform));
 140     }
 141 
 142 
 143     private boolean matchesIgnoredPath(String prefixedName) {
 144         Vector rv = new Vector();
 145         collectRelevantVectors(rv, "IgnorePath");
 146         for (Iterator i = rv.iterator(); i.hasNext(); ) {
 147             String pathPart = (String) i.next();
 148             if (prefixedName.contains(Util.normalize(pathPart)))  {
 149                 return true;
 150             }
 151         }
 152         return false;
 153     }
 154 
 155     void addAll(Iterator i, Hashtable hash,
 156                 WinGammaPlatform platform, DirectoryTree tree,
 157                 Vector preferredPaths, Vector filesNotFound, Vector filesDuplicate) {
 158         for (; i.hasNext(); ) {
 159             String fileName = (String) i.next();
 160             if (lookupHashFieldInContext("IgnoreFile", fileName) == null) {
 161                 String prefixedName = platform.envVarPrefixedFileName(fileName,
 162                                                                       0, /* ignored */
 163                                                                       tree,
 164                                                                       preferredPaths,
 165                                                                       filesNotFound,
 166                                                                       filesDuplicate);
 167                 if (prefixedName != null) {
 168                     prefixedName = Util.normalize(prefixedName);
 169                     if (!matchesIgnoredPath(prefixedName)) {
 170                         addTo(hash, prefixedName, fileName);
 171                     }
 172                 }
 173             }
 174         }
 175     }
 176 
 177     void addTo(Hashtable ht, String key, String value) {
 178         ht.put(expandFormat(key), expandFormat(value));
 179     }
 180 
 181     Hashtable computeAllFiles(WinGammaPlatform platform) {
 182         Hashtable rv = new Hashtable();
 183         DirectoryTree tree = getSourceTree(get("SourceBase"), getFieldString(null, "StartAt"));
 184         Vector preferredPaths = getPreferredPaths();
 185 
 186         // Hold errors until end
 187         Vector filesNotFound = new Vector();
 188         Vector filesDuplicate = new Vector();
 189 
 190         Vector includedFiles = new Vector();
 191 
 192         // find all files
 193         Vector dirs = getSourceIncludes();
 194         for (Iterator i = dirs.iterator(); i.hasNext(); ) {
 195             String dir = (String)i.next();
 196             DirectoryTree subtree = getSourceTree(dir, null);
 197             for (Iterator fi = subtree.getFileIterator(); fi.hasNext(); ) {
 198                 String name = ((File)fi.next()).getName();
 199                 includedFiles.add(name);
 200             }
 201         }
 202         addAll(includedFiles.iterator(), rv,
 203                platform, tree,
 204                preferredPaths, filesNotFound, filesDuplicate);
 205 
 206         Vector addFiles = new Vector();
 207         collectRelevantVectors(addFiles, "AdditionalFile");
 208         addAll(addFiles.iterator(), rv,
 209                platform, tree,
 210                preferredPaths, filesNotFound, filesDuplicate);
 211 
 212         collectRelevantHashes(rv, "AdditionalGeneratedFile");
 213 
 214         if ((filesNotFound.size() != 0) ||
 215             (filesDuplicate.size() != 0)) {
 216             System.err.println("Error: some files were not found or " +
 217                                "appeared in multiple subdirectories of " +
 218                                "directory " + get("SourceBase") + " and could not " +
 219                                "be resolved with os_family and arch.");
 220             if (filesNotFound.size() != 0) {
 221                 System.err.println("Files not found:");
 222                 for (Iterator iter = filesNotFound.iterator();
 223                      iter.hasNext(); ) {
 224                     System.err.println("  " + (String) iter.next());
 225                 }
 226             }
 227             if (filesDuplicate.size() != 0) {
 228                 System.err.println("Duplicate files:");
 229                 for (Iterator iter = filesDuplicate.iterator();
 230                      iter.hasNext(); ) {
 231                     System.err.println("  " + (String) iter.next());
 232                 }
 233             }
 234             throw new RuntimeException();
 235         }
 236 
 237         return rv;
 238     }
 239 
 240     void initDefaultDefines(Vector defines) {
 241         Vector sysDefines = new Vector();
 242         sysDefines.add("WIN32");
 243         sysDefines.add("_WINDOWS");
 244         sysDefines.add("HOTSPOT_BUILD_USER=\\\""+System.getProperty("user.name")+"\\\"");
 245         sysDefines.add("HOTSPOT_BUILD_TARGET=\\\""+get("Build")+"\\\"");
 246         sysDefines.add("INCLUDE_TRACE");
 247         sysDefines.add("_JNI_IMPLEMENTATION_");
 248         if (vars.get("PlatformName").equals("Win32")) {
 249             sysDefines.add("HOTSPOT_LIB_ARCH=\\\"i386\\\"");
 250         } else {
 251             sysDefines.add("HOTSPOT_LIB_ARCH=\\\"amd64\\\"");
 252         }
 253 
 254         sysDefines.addAll(defines);
 255 
 256         put("Define", sysDefines);
 257     }
 258 
 259     String get(String key) {
 260         return (String)vars.get(key);
 261     }
 262 
 263     Vector getV(String key) {
 264         return (Vector)vars.get(key);
 265     }
 266 
 267     Object getO(String key) {
 268         return vars.get(key);
 269     }
 270 
 271     Hashtable getH(String key) {
 272         return (Hashtable)vars.get(key);
 273     }
 274 
 275     Object getFieldInContext(String field) {
 276         for (int i=0; i<context.length; i++) {
 277             Object rv = getField(context[i], field);
 278             if (rv != null) {
 279                 return rv;
 280             }
 281         }
 282         return null;
 283     }
 284 
 285     Object lookupHashFieldInContext(String field, String key) {
 286         for (int i=0; i<context.length; i++) {
 287             Hashtable ht = (Hashtable)getField(context[i], field);
 288             if (ht != null) {
 289                 Object rv = ht.get(key);
 290                 if (rv != null) {
 291                     return rv;
 292                 }
 293             }
 294         }
 295         return null;
 296     }
 297 
 298     void put(String key, String value) {
 299         vars.put(key, value);
 300     }
 301 
 302     void put(String key, Vector vvalue) {
 303         vars.put(key, vvalue);
 304     }
 305 
 306     void add(String key, Vector vvalue) {
 307         getV(key).addAll(vvalue);
 308     }
 309 
 310     String flavour() {
 311         return get("Flavour");
 312     }
 313 
 314     String build() {
 315         return get("Build");
 316     }
 317 
 318     Object getSpecificField(String field) {
 319         return getField(get("Id"), field);
 320     }
 321 
 322     void putSpecificField(String field, Object value) {
 323         putField(get("Id"), field, value);
 324     }
 325 
 326     void collectRelevantVectors(Vector rv, String field) {
 327         for (int i = 0; i < context.length; i++) {
 328             Vector v = getFieldVector(context[i], field);
 329             if (v != null) {
 330                 for (Iterator j=v.iterator(); j.hasNext(); ) {
 331                     String val = (String)j.next();
 332                     rv.add(expandFormat(val));
 333                 }
 334             }
 335         }
 336     }
 337 
 338     void collectRelevantHashes(Hashtable rv, String field) {
 339         for (int i = 0; i < context.length; i++) {
 340             Hashtable v = (Hashtable)getField(context[i], field);
 341             if (v != null) {
 342                 for (Enumeration e=v.keys(); e.hasMoreElements(); ) {
 343                     String key = (String)e.nextElement();
 344                     String val =  (String)v.get(key);
 345                     addTo(rv, key, val);
 346                 }
 347             }
 348         }
 349     }
 350 
 351 
 352     Vector getDefines() {
 353         Vector rv = new Vector();
 354         collectRelevantVectors(rv, "Define");
 355         return rv;
 356     }
 357 
 358     Vector getIncludes() {
 359         Vector rv = new Vector();
 360 
 361         collectRelevantVectors(rv, "AbsoluteInclude");
 362 
 363         rv.addAll(getSourceIncludes());
 364 
 365         return rv;
 366     }
 367 
 368     private Vector getSourceIncludes() {
 369         Vector rv = new Vector();
 370         Vector ri = new Vector();
 371         String sourceBase = getFieldString(null, "SourceBase");
 372         collectRelevantVectors(ri, "RelativeInclude");
 373         for (Iterator i = ri.iterator(); i.hasNext(); ) {
 374             String f = (String)i.next();
 375             rv.add(sourceBase + Util.sep + f);
 376         }
 377         return rv;
 378     }
 379 
 380     static Hashtable cfgData = new Hashtable();
 381     static Hashtable globalData = new Hashtable();
 382 
 383     static boolean appliesToTieredBuild(String cfg) {
 384         return (cfg != null &&
 385                 (cfg.startsWith("compiler1") ||
 386                  cfg.startsWith("compiler2")));
 387     }
 388 
 389     // Filters out the IgnoreFile and IgnorePaths since they are
 390     // handled specially for tiered builds.
 391     static boolean appliesToTieredBuild(String cfg, String key) {
 392         return (appliesToTieredBuild(cfg))&& (key != null && !key.startsWith("Ignore"));
 393     }
 394 
 395     static String getTieredBuildCfg(String cfg) {
 396         assert appliesToTieredBuild(cfg) : "illegal configuration " + cfg;
 397         return "tiered" + cfg.substring(9);
 398     }
 399 
 400     static Object getField(String cfg, String field) {
 401         if (cfg == null) {
 402             return globalData.get(field);
 403         }
 404 
 405         Hashtable ht =  (Hashtable)cfgData.get(cfg);
 406         return ht == null ? null : ht.get(field);
 407     }
 408 
 409     static String getFieldString(String cfg, String field) {
 410         return (String)getField(cfg, field);
 411     }
 412 
 413     static Vector getFieldVector(String cfg, String field) {
 414         return (Vector)getField(cfg, field);
 415     }
 416 
 417     static void putField(String cfg, String field, Object value) {
 418         putFieldImpl(cfg, field, value);
 419         if (appliesToTieredBuild(cfg, field)) {
 420             putFieldImpl(getTieredBuildCfg(cfg), field, value);
 421         }
 422     }
 423 
 424     private static void putFieldImpl(String cfg, String field, Object value) {
 425         if (cfg == null) {
 426             globalData.put(field, value);
 427             return;
 428         }
 429 
 430         Hashtable ht = (Hashtable)cfgData.get(cfg);
 431         if (ht == null) {
 432             ht = new Hashtable();
 433             cfgData.put(cfg, ht);
 434         }
 435 
 436         ht.put(field, value);
 437     }
 438 
 439     static Object getFieldHash(String cfg, String field, String name) {
 440         Hashtable ht = (Hashtable)getField(cfg, field);
 441 
 442         return ht == null ? null : ht.get(name);
 443     }
 444 
 445     static void putFieldHash(String cfg, String field, String name, Object val) {
 446         putFieldHashImpl(cfg, field, name, val);
 447         if (appliesToTieredBuild(cfg, field)) {
 448             putFieldHashImpl(getTieredBuildCfg(cfg), field, name, val);
 449         }
 450     }
 451 
 452     private static void putFieldHashImpl(String cfg, String field, String name, Object val) {
 453         Hashtable ht = (Hashtable)getField(cfg, field);
 454 
 455         if (ht == null) {
 456             ht = new Hashtable();
 457             putFieldImpl(cfg, field, ht);
 458         }
 459 
 460         ht.put(name, val);
 461     }
 462 
 463     static void addFieldVector(String cfg, String field, String element) {
 464         addFieldVectorImpl(cfg, field, element);
 465         if (appliesToTieredBuild(cfg, field)) {
 466             addFieldVectorImpl(getTieredBuildCfg(cfg), field, element);
 467         }
 468     }
 469 
 470     private static void addFieldVectorImpl(String cfg, String field, String element) {
 471         Vector v = (Vector)getField(cfg, field);
 472 
 473         if (v == null) {
 474             v = new Vector();
 475             putFieldImpl(cfg, field, v);
 476         }
 477 
 478         v.add(element);
 479     }
 480 
 481     String expandFormat(String format) {
 482         if (format == null) {
 483             return null;
 484         }
 485 
 486         if (format.indexOf('%') == -1) {
 487             return format;
 488         }
 489 
 490         StringBuffer sb = new StringBuffer();
 491         int len = format.length();
 492         for (int i=0; i<len; i++) {
 493             char ch = format.charAt(i);
 494             if (ch == '%') {
 495                 char ch1 = format.charAt(i+1);
 496                 switch (ch1) {
 497                 case '%':
 498                     sb.append(ch1);
 499                     break;
 500                 case 'b':
 501                     sb.append(build());
 502                     break;
 503                 case 'f':
 504                     sb.append(flavour());
 505                     break;
 506                 default:
 507                     sb.append(ch);
 508                     sb.append(ch1);
 509                 }
 510                 i++;
 511             } else {
 512                 sb.append(ch);
 513             }
 514         }
 515 
 516         return sb.toString();
 517     }
 518 }
 519 
 520 abstract class GenericDebugConfig extends BuildConfig {
 521     abstract String getOptFlag();
 522 
 523     protected void init(Vector includes, Vector defines) {
 524         defines.add("_DEBUG");
 525         defines.add("ASSERT");
 526 
 527         super.init(includes, defines);
 528 
 529         getV("CompilerFlags").addAll(getCI().getDebugCompilerFlags(getOptFlag()));
 530         getV("LinkerFlags").addAll(getCI().getDebugLinkerFlags());
 531    }
 532 }
 533 
 534 abstract class GenericDebugNonKernelConfig extends GenericDebugConfig {
 535     protected void init(Vector includes, Vector defines) {
 536         super.init(includes, defines);
 537         getCI().getAdditionalNonKernelLinkerFlags(getV("LinkerFlags"));
 538    }
 539 }
 540 
 541 class C1DebugConfig extends GenericDebugNonKernelConfig {
 542     String getOptFlag() {
 543         return getCI().getNoOptFlag();
 544     }
 545 
 546     C1DebugConfig() {
 547         initNames("compiler1", "debug", "jvm.dll");
 548         init(getIncludes(), getDefines());
 549     }
 550 }
 551 
 552 class C1FastDebugConfig extends GenericDebugNonKernelConfig {
 553     String getOptFlag() {
 554         return getCI().getOptFlag();
 555     }
 556 
 557     C1FastDebugConfig() {
 558         initNames("compiler1", "fastdebug", "jvm.dll");
 559         init(getIncludes(), getDefines());
 560     }
 561 }
 562 
 563 class C2DebugConfig extends GenericDebugNonKernelConfig {
 564     String getOptFlag() {
 565         return getCI().getNoOptFlag();
 566     }
 567 
 568     C2DebugConfig() {
 569         initNames("compiler2", "debug", "jvm.dll");
 570         init(getIncludes(), getDefines());
 571     }
 572 }
 573 
 574 class C2FastDebugConfig extends GenericDebugNonKernelConfig {
 575     String getOptFlag() {
 576         return getCI().getOptFlag();
 577     }
 578 
 579     C2FastDebugConfig() {
 580         initNames("compiler2", "fastdebug", "jvm.dll");
 581         init(getIncludes(), getDefines());
 582     }
 583 }
 584 
 585 class TieredDebugConfig extends GenericDebugNonKernelConfig {
 586     String getOptFlag() {
 587         return getCI().getNoOptFlag();
 588     }
 589 
 590     TieredDebugConfig() {
 591         initNames("tiered", "debug", "jvm.dll");
 592         init(getIncludes(), getDefines());
 593     }
 594 }
 595 
 596 class TieredFastDebugConfig extends GenericDebugNonKernelConfig {
 597     String getOptFlag() {
 598         return getCI().getOptFlag();
 599     }
 600 
 601     TieredFastDebugConfig() {
 602         initNames("tiered", "fastdebug", "jvm.dll");
 603         init(getIncludes(), getDefines());
 604     }
 605 }
 606 
 607 
 608 abstract class ProductConfig extends BuildConfig {
 609     protected void init(Vector includes, Vector defines) {
 610         defines.add("NDEBUG");
 611         defines.add("PRODUCT");
 612 
 613         super.init(includes, defines);
 614 
 615         getV("CompilerFlags").addAll(getCI().getProductCompilerFlags());
 616         getV("LinkerFlags").addAll(getCI().getProductLinkerFlags());
 617     }
 618 }
 619 
 620 class C1ProductConfig extends ProductConfig {
 621     C1ProductConfig() {
 622         initNames("compiler1", "product", "jvm.dll");
 623         init(getIncludes(), getDefines());
 624     }
 625 }
 626 
 627 class C2ProductConfig extends ProductConfig {
 628     C2ProductConfig() {
 629         initNames("compiler2", "product", "jvm.dll");
 630         init(getIncludes(), getDefines());
 631     }
 632 }
 633 
 634 class TieredProductConfig extends ProductConfig {
 635     TieredProductConfig() {
 636         initNames("tiered", "product", "jvm.dll");
 637         init(getIncludes(), getDefines());
 638     }
 639 }
 640 
 641 
 642 class CoreDebugConfig extends GenericDebugNonKernelConfig {
 643     String getOptFlag() {
 644         return getCI().getNoOptFlag();
 645     }
 646 
 647     CoreDebugConfig() {
 648         initNames("core", "debug", "jvm.dll");
 649         init(getIncludes(), getDefines());
 650     }
 651 }
 652 
 653 
 654 class CoreFastDebugConfig extends GenericDebugNonKernelConfig {
 655     String getOptFlag() {
 656         return getCI().getOptFlag();
 657     }
 658 
 659     CoreFastDebugConfig() {
 660         initNames("core", "fastdebug", "jvm.dll");
 661         init(getIncludes(), getDefines());
 662     }
 663 }
 664 
 665 
 666 class CoreProductConfig extends ProductConfig {
 667     CoreProductConfig() {
 668         initNames("core", "product", "jvm.dll");
 669         init(getIncludes(), getDefines());
 670     }
 671 }
 672 
 673 class KernelDebugConfig extends GenericDebugConfig {
 674     String getOptFlag() {
 675         return getCI().getNoOptFlag();
 676     }
 677 
 678     KernelDebugConfig() {
 679         initNames("kernel", "debug", "jvm.dll");
 680         init(getIncludes(), getDefines());
 681     }
 682 }
 683 
 684 
 685 class KernelFastDebugConfig extends GenericDebugConfig {
 686     String getOptFlag() {
 687         return getCI().getOptFlag();
 688     }
 689 
 690     KernelFastDebugConfig() {
 691         initNames("kernel", "fastdebug", "jvm.dll");
 692         init(getIncludes(), getDefines());
 693     }
 694 }
 695 
 696 
 697 class KernelProductConfig extends ProductConfig {
 698     KernelProductConfig() {
 699         initNames("kernel", "product", "jvm.dll");
 700         init(getIncludes(), getDefines());
 701     }
 702 }
 703 abstract class CompilerInterface {
 704     abstract Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir);
 705     abstract Vector getBaseLinkerFlags(String outDir, String outDll, String platformName);
 706     abstract Vector getDebugCompilerFlags(String opt);
 707     abstract Vector getDebugLinkerFlags();
 708     abstract void   getAdditionalNonKernelLinkerFlags(Vector rv);
 709     abstract Vector getProductCompilerFlags();
 710     abstract Vector getProductLinkerFlags();
 711     abstract String getOptFlag();
 712     abstract String getNoOptFlag();
 713     abstract String makeCfgName(String flavourBuild, String platformName);
 714 
 715     void addAttr(Vector receiver, String attr, String value) {
 716         receiver.add(attr); receiver.add(value);
 717     }
 718     void extAttr(Vector receiver, String attr, String value) {
 719         int attr_pos=receiver.indexOf(attr) ;
 720         if ( attr_pos == -1) {
 721           // If attr IS NOT present in the Vector - add it
 722           receiver.add(attr); receiver.add(value);
 723         } else {
 724           // If attr IS present in the Vector - append value to it
 725           receiver.set(attr_pos+1,receiver.get(attr_pos+1)+value);
 726         }
 727     }
 728 }