Пример #1
0
 protected void doFieldWrite(
     WalkContext context, int receiver, CAstNode elt, CAstNode parent, int rval) {
   this.visit(elt, context, this);
   if (elt.getKind() == CAstNode.CONSTANT && elt.getValue() instanceof String) {
     String field = (String) elt.getValue();
     if (isPrologueScript(context) && "__proto__".equals(field)) {
       context.cfg().addInstruction(((JSInstructionFactory) insts).SetPrototype(receiver, rval));
       return;
     }
   }
   /*
     } else {
       context.currentScope().getConstantValue(field);
       SSAPutInstruction put = ((JSInstructionFactory) insts).PutInstruction(receiver, rval, field);
       try {
         assert field.equals(put.getDeclaredField().getName().toUnicodeString());
       } catch (UTFDataFormatException e) {
         Assertions.UNREACHABLE();
       }
       context.cfg().addInstruction(put);
     }
   } else {
   */
   context
       .cfg()
       .addInstruction(
           ((JSInstructionFactory) insts).PropertyWrite(receiver, context.getValue(elt), rval));
   // }
 }
Пример #2
0
  protected void leaveInstanceOf(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
    WalkContext context = (WalkContext) c;
    int result = context.getValue(n);

    visit(n.getChild(0), context, visitor);
    int value = context.getValue(n.getChild(0));

    visit(n.getChild(1), context, visitor);
    int type = context.getValue(n.getChild(1));

    context.cfg().addInstruction(new JavaScriptInstanceOf(result, value, type));
  }
Пример #3
0
  /**
   * create a CAstNode l representing a loop that traverses the prototype chain from receiver
   * searching for the constant property element. update nodeMap to map root to an expression that
   * reads the property from the right node.
   *
   * @param root
   * @param receiver
   * @param element
   * @param context
   * @param nodeMap
   * @return
   */
  private CAstNode makeConstRead(
      CAstNode root,
      CAstNode receiver,
      CAstNode element,
      RewriteContext context,
      Map<Pair<CAstNode, ExpanderKey>, CAstNode> nodeMap) {
    CAstNode get, result;
    String receiverTemp = TEMP_NAME + (readTempCounter++);
    String elt = (String) element.getValue();
    if (elt.equals("prototype") || elt.equals("__proto__")) {
      result =
          Ast.makeNode(
              CAstNode.BLOCK_EXPR,
              get = Ast.makeNode(CAstNode.OBJECT_REF, receiver, Ast.makeConstant(elt)));
    } else {

      if (context.inAssignment()) {
        context.setAssign(
            Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)), Ast.makeConstant(elt));
      }

      result =
          Ast.makeNode(
              CAstNode.BLOCK_EXPR,
              // declare loop variable and initialize to the receiver
              Ast.makeNode(
                  CAstNode.DECL_STMT,
                  Ast.makeConstant(new InternalCAstSymbol(receiverTemp, false, false)),
                  receiver),
              Ast.makeNode(
                  CAstNode.LOOP,
                  // while the desired property of the loop variable is not
                  // defined...
                  Ast.makeNode(
                      CAstNode.UNARY_EXPR,
                      CAstOperator.OP_NOT,
                      Ast.makeNode(
                          CAstNode.IS_DEFINED_EXPR,
                          Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
                          Ast.makeConstant(elt))),
                  // set the loop variable to be its prototype
                  Ast.makeNode(
                      CAstNode.ASSIGN,
                      Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
                      Ast.makeNode(
                          CAstNode.OBJECT_REF,
                          Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
                          Ast.makeConstant("__proto__")))),
              get =
                  Ast.makeNode(
                      CAstNode.OBJECT_REF,
                      Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
                      Ast.makeConstant(elt)));
    }

    nodeMap.put(Pair.make(root, context.key()), result);
    nodeMap.put(Pair.make(root, ExpanderKey.EXTRA), get);

    return result;
  }
Пример #4
0
  protected void doFieldRead(
      WalkContext context, int result, int receiver, CAstNode elt, CAstNode readNode) {
    this.visit(elt, context, this);
    int x = context.currentScope().allocateTempValue();

    context.cfg().addInstruction(((JSInstructionFactory) insts).AssignInstruction(x, receiver));

    context.cfg().addInstruction(((JSInstructionFactory) insts).PrototypeLookup(x, x));

    if (elt.getKind() == CAstNode.CONSTANT && elt.getValue() instanceof String) {
      String field = (String) elt.getValue();
      // symtab needs to have this value
      context.currentScope().getConstantValue(field);
      context.cfg().addInstruction(((JSInstructionFactory) insts).GetInstruction(result, x, field));
    } else {
      context
          .cfg()
          .addInstruction(
              ((JSInstructionFactory) insts).PropertyRead(result, x, context.getValue(elt)));
    }

    // generate code to handle read of non-existent property
    if (context.getControlFlow().getMappedNodes().contains(readNode)) {
      context.cfg().addPreNode(readNode, context.getUnwindState());

      context.cfg().newBlock(true);

      if (context.getControlFlow().getTarget(readNode, JavaScriptTypes.TypeError) != null)
        context
            .cfg()
            .addPreEdge(
                readNode,
                context.getControlFlow().getTarget(readNode, JavaScriptTypes.TypeError),
                true);
      else context.cfg().addPreEdgeToExit(readNode, true);
    }
  }
Пример #5
0
  protected void doIsFieldDefined(WalkContext context, int result, int ref, CAstNode f) {
    if (f.getKind() == CAstNode.CONSTANT && f.getValue() instanceof String) {
      String field = (String) f.getValue();

      FieldReference fieldRef =
          FieldReference.findOrCreate(
              JavaScriptTypes.Root,
              Atom.findOrCreateUnicodeAtom((String) field),
              JavaScriptTypes.Root);

      context
          .cfg()
          .addInstruction(
              ((JSInstructionFactory) insts).IsDefinedInstruction(result, ref, fieldRef));

    } else {

      context
          .cfg()
          .addInstruction(
              ((JSInstructionFactory) insts)
                  .IsDefinedInstruction(result, ref, context.getValue(f)));
    }
  }
Пример #6
0
  protected void doCall(
      WalkContext context,
      CAstNode call,
      int result,
      int exception,
      CAstNode name,
      int receiver,
      int[] arguments) {
    MethodReference ref =
        name.getValue().equals("ctor")
            ? JavaScriptMethods.ctorReference
            : name.getValue().equals("dispatch")
                ? JavaScriptMethods.dispatchReference
                : AstMethodReference.fnReference(JavaScriptTypes.CodeBody);

    context
        .cfg()
        .addInstruction(
            ((JSInstructionFactory) insts)
                .Invoke(
                    receiver,
                    result,
                    arguments,
                    exception,
                    new JSCallSiteReference(ref, context.cfg().getCurrentInstruction())));

    context.cfg().addPreNode(call, context.getUnwindState());

    // this new block is for the normal termination case
    context.cfg().newBlock(true);

    // exceptional case: flow to target given in CAst, or if null, the exit node
    if (context.getControlFlow().getTarget(call, null) != null)
      context.cfg().addPreEdge(call, context.getControlFlow().getTarget(call, null), true);
    else context.cfg().addPreEdgeToExit(call, true);
  }
Пример #7
0
  protected boolean doVisit(CAstNode n, WalkContext cntxt, CAstVisitor<WalkContext> visitor) {
    WalkContext context = (WalkContext) cntxt;
    switch (n.getKind()) {
      case CAstNode.TYPE_OF:
        {
          int result = context.currentScope().allocateTempValue();

          this.visit(n.getChild(0), context, this);
          int ref = context.getValue(n.getChild(0));

          context
              .cfg()
              .addInstruction(((JSInstructionFactory) insts).TypeOfInstruction(result, ref));

          context.setValue(n, result);
          return true;
        }

      case JavaScriptCAstNode.ENTER_WITH:
      case JavaScriptCAstNode.EXIT_WITH:
        {
          this.visit(n.getChild(0), context, this);
          int ref = context.getValue(n.getChild(0));

          context
              .cfg()
              .addInstruction(
                  ((JSInstructionFactory) insts)
                      .WithRegion(ref, n.getKind() == JavaScriptCAstNode.ENTER_WITH));

          return true;
        }
      default:
        {
          return false;
        }
    }
  }
Пример #8
0
  protected void doPrimitive(int resultVal, WalkContext context, CAstNode primitiveCall) {
    try {
      String name = (String) primitiveCall.getChild(0).getValue();
      if (name.equals("GlobalNaN")) {
        context
            .cfg()
            .addInstruction(
                ((JSInstructionFactory) insts)
                    .AssignInstruction(
                        resultVal, context.currentScope().getConstantValue(new Float(Float.NaN))));
      } else if (name.equals("GlobalInfinity")) {
        context
            .cfg()
            .addInstruction(
                ((JSInstructionFactory) insts)
                    .AssignInstruction(
                        resultVal,
                        context
                            .currentScope()
                            .getConstantValue(new Float(Float.POSITIVE_INFINITY))));
      } else if (name.equals("MathE")) {
        context
            .cfg()
            .addInstruction(
                ((JSInstructionFactory) insts)
                    .AssignInstruction(
                        resultVal, context.currentScope().getConstantValue(new Double(Math.E))));
      } else if (name.equals("MathPI")) {
        context
            .cfg()
            .addInstruction(
                ((JSInstructionFactory) insts)
                    .AssignInstruction(
                        resultVal, context.currentScope().getConstantValue(new Double(Math.PI))));
      } else if (name.equals("MathSQRT1_2")) {
        context
            .cfg()
            .addInstruction(
                ((JSInstructionFactory) insts)
                    .AssignInstruction(
                        resultVal,
                        context.currentScope().getConstantValue(new Double(Math.sqrt(.5)))));
      } else if (name.equals("MathSQRT2")) {
        context
            .cfg()
            .addInstruction(
                ((JSInstructionFactory) insts)
                    .AssignInstruction(
                        resultVal,
                        context.currentScope().getConstantValue(new Double(Math.sqrt(2)))));
      } else if (name.equals("MathLN2")) {
        context
            .cfg()
            .addInstruction(
                ((JSInstructionFactory) insts)
                    .AssignInstruction(
                        resultVal,
                        context.currentScope().getConstantValue(new Double(Math.log(2)))));
      } else if (name.equals("MathLN10")) {
        context
            .cfg()
            .addInstruction(
                ((JSInstructionFactory) insts)
                    .AssignInstruction(
                        resultVal,
                        context.currentScope().getConstantValue(new Double(Math.log(10)))));
      } else if (name.equals("NewObject")) {
        doNewObject(context, null, resultVal, "Object", null);

      } else if (name.equals("NewArray")) {
        doNewObject(context, null, resultVal, "Array", null);

      } else if (name.equals("NewString")) {
        doPrimitiveNew(context, resultVal, "String");

      } else if (name.equals("NewNumber")) {
        doPrimitiveNew(context, resultVal, "Number");

      } else if (name.equals("NewRegExp")) {
        doPrimitiveNew(context, resultVal, "RegExp");

      } else if (name.equals("NewFunction")) {
        doNewObject(context, null, resultVal, "Function", null);

      } else if (name.equals("NewUndefined")) {
        doNewObject(context, null, resultVal, "Undefined", null);

      } else {
        context
            .cfg()
            .addInstruction(
                ((JSInstructionFactory) insts)
                    .AssignInstruction(resultVal, context.currentScope().getConstantValue(null)));
      }
    } catch (ClassCastException e) {
      throw new RuntimeException(
          "Cannot translate primitive " + primitiveCall.getChild(0).getValue());
    }
  }
Пример #9
0
  @Override
  protected CAstNode copyNodes(
      CAstNode root,
      final CAstControlFlowMap cfg,
      RewriteContext context,
      Map<Pair<CAstNode, ExpanderKey>, CAstNode> nodeMap) {
    int kind = root.getKind();

    if (kind == CAstNode.OBJECT_REF && context.inRead()) {
      // if we see a property access (OBJECT_REF) in a read context, transform
      // to a loop traversing the prototype chain
      CAstNode readLoop;
      CAstNode receiver = copyNodes(root.getChild(0), cfg, READ, nodeMap);
      CAstNode element = copyNodes(root.getChild(1), cfg, READ, nodeMap);
      if (element.getKind() == CAstNode.CONSTANT && element.getValue() instanceof String) {
        readLoop = makeConstRead(root, receiver, element, context, nodeMap);
      } else {
        readLoop = makeVarRead(root, receiver, element, context, nodeMap);
      }
      return readLoop;

    } else if (kind == CAstNode.ASSIGN_PRE_OP || kind == CAstNode.ASSIGN_POST_OP) {
      // handle cases like x.f++, represented as ASSIGN_POST_OP(x.f,1,+)
      AssignPreOrPostOpContext ctxt = new AssignPreOrPostOpContext();
      // generate loop for the first child (x.f for example), keeping the loop var and element var
      // in ctxt
      CAstNode lval = copyNodes(root.getChild(0), cfg, ctxt, nodeMap);
      CAstNode rval = copyNodes(root.getChild(1), cfg, READ, nodeMap);
      CAstNode op = copyNodes(root.getChild(2), cfg, READ, nodeMap);
      if (ctxt.receiverTemp != null) { // if we found a nested property access
        String temp1 = TEMP_NAME + (readTempCounter++);
        String temp2 = TEMP_NAME + (readTempCounter++);
        CAstNode copy =
            Ast.makeNode(
                CAstNode.BLOCK_EXPR,
                // assign lval to temp1 (where lval is a block that includes the prototype chain
                // loop)
                Ast.makeNode(
                    CAstNode.DECL_STMT,
                    Ast.makeConstant(new InternalCAstSymbol(temp1, true, false)),
                    lval),
                // ? --MS
                // rval,
                // assign temp2 the new value to be assigned
                Ast.makeNode(
                    CAstNode.DECL_STMT,
                    Ast.makeConstant(new InternalCAstSymbol(temp2, true, false)),
                    Ast.makeNode(
                        CAstNode.BINARY_EXPR,
                        op,
                        Ast.makeNode(CAstNode.VAR, Ast.makeConstant(temp1)),
                        rval)),
                // write temp2 into the property
                Ast.makeNode(
                    CAstNode.ASSIGN,
                    Ast.makeNode(CAstNode.OBJECT_REF, ctxt.receiverTemp, ctxt.elementTemp),
                    Ast.makeNode(CAstNode.VAR, Ast.makeConstant(temp2))),
                // final value depends on whether we had a pre op or post op
                Ast.makeNode(
                    CAstNode.VAR,
                    Ast.makeConstant((kind == CAstNode.ASSIGN_PRE_OP) ? temp2 : temp1)));
        nodeMap.put(Pair.make(root, context.key()), copy);
        return copy;
      } else {
        CAstNode copy = Ast.makeNode(kind, lval, rval, op);
        nodeMap.put(Pair.make(root, context.key()), copy);
        return copy;
      }

    } else if (kind == CAstNode.ASSIGN) {
      // use ASSIGN context for LHS so we don't translate property accesses there
      CAstNode copy =
          Ast.makeNode(
              CAstNode.ASSIGN,
              copyNodes(root.getChild(0), cfg, ASSIGN, nodeMap),
              copyNodes(root.getChild(1), cfg, READ, nodeMap));
      nodeMap.put(Pair.make(root, context.key()), copy);
      return copy;

    } else if (kind == CAstNode.BLOCK_EXPR) {
      CAstNode children[] = new CAstNode[root.getChildCount()];
      int last = (children.length - 1);
      for (int i = 0; i < last; i++) {
        children[i] = copyNodes(root.getChild(i), cfg, READ, nodeMap);
      }
      children[last] = copyNodes(root.getChild(last), cfg, context, nodeMap);

      CAstNode copy = Ast.makeNode(CAstNode.BLOCK_EXPR, children);
      nodeMap.put(Pair.make(root, context.key()), copy);
      return copy;

    } else if (root.getKind() == CAstNode.CONSTANT) {
      CAstNode copy = Ast.makeConstant(root.getValue());
      nodeMap.put(Pair.make(root, context.key()), copy);
      return copy;

    } else if (root.getKind() == CAstNode.OPERATOR) {
      nodeMap.put(Pair.make(root, context.key()), root);
      return root;

    } else {
      CAstNode children[] = new CAstNode[root.getChildCount()];
      for (int i = 0; i < children.length; i++) {
        children[i] = copyNodes(root.getChild(i), cfg, READ, nodeMap);
      }
      for (Object label : cfg.getTargetLabels(root)) {
        if (label instanceof CAstNode) {
          copyNodes((CAstNode) label, cfg, READ, nodeMap);
        }
      }
      CAstNode copy = Ast.makeNode(kind, children);
      nodeMap.put(Pair.make(root, context.key()), copy);
      return copy;
    }
  }