2007-02-02 17:25:09 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* Copyright (c) 2002 - 2006 IBM Corporation.
|
|
|
|
* All rights reserved. This program and the accompanying materials
|
|
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
|
|
* which accompanies this distribution, and is available at
|
|
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
|
|
*
|
|
|
|
* Contributors:
|
|
|
|
* IBM Corporation - initial API and implementation
|
|
|
|
*****************************************************************************/
|
|
|
|
package com.ibm.wala.cast.js.translator;
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.Collections;
|
2013-04-11 01:09:10 +00:00
|
|
|
import java.util.Map;
|
2014-02-09 02:34:34 +00:00
|
|
|
import java.util.Set;
|
2013-04-11 01:09:10 +00:00
|
|
|
|
2007-04-24 13:50:32 +00:00
|
|
|
import com.ibm.wala.cast.ir.translator.AstTranslator;
|
|
|
|
import com.ibm.wala.cast.js.loader.JSCallSiteReference;
|
|
|
|
import com.ibm.wala.cast.js.loader.JavaScriptLoader;
|
2009-04-10 18:33:07 +00:00
|
|
|
import com.ibm.wala.cast.js.ssa.JSInstructionFactory;
|
2009-01-27 17:40:11 +00:00
|
|
|
import com.ibm.wala.cast.js.ssa.JavaScriptInstanceOf;
|
2014-02-09 02:34:34 +00:00
|
|
|
import com.ibm.wala.cast.js.ssa.PrototypeLookup;
|
2007-04-24 13:50:32 +00:00
|
|
|
import com.ibm.wala.cast.js.types.JavaScriptMethods;
|
|
|
|
import com.ibm.wala.cast.js.types.JavaScriptTypes;
|
|
|
|
import com.ibm.wala.cast.loader.AstMethod.DebuggingInformation;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.cast.tree.CAstEntity;
|
|
|
|
import com.ibm.wala.cast.tree.CAstNode;
|
|
|
|
import com.ibm.wala.cast.tree.CAstSymbol;
|
|
|
|
import com.ibm.wala.cast.tree.CAstType;
|
|
|
|
import com.ibm.wala.cast.tree.impl.CAstSymbolImpl;
|
2007-04-24 13:50:32 +00:00
|
|
|
import com.ibm.wala.cast.tree.visit.CAstVisitor;
|
|
|
|
import com.ibm.wala.cast.types.AstMethodReference;
|
|
|
|
import com.ibm.wala.cfg.AbstractCFG;
|
2013-04-11 01:09:10 +00:00
|
|
|
import com.ibm.wala.cfg.IBasicBlock;
|
2007-04-24 13:50:32 +00:00
|
|
|
import com.ibm.wala.classLoader.NewSiteReference;
|
2014-02-09 02:34:34 +00:00
|
|
|
import com.ibm.wala.ssa.SSAInstruction;
|
2007-04-24 13:50:32 +00:00
|
|
|
import com.ibm.wala.ssa.SymbolTable;
|
|
|
|
import com.ibm.wala.types.FieldReference;
|
|
|
|
import com.ibm.wala.types.MethodReference;
|
|
|
|
import com.ibm.wala.types.TypeName;
|
|
|
|
import com.ibm.wala.types.TypeReference;
|
2007-02-02 17:25:09 +00:00
|
|
|
import com.ibm.wala.util.debug.Assertions;
|
2008-01-24 22:06:02 +00:00
|
|
|
import com.ibm.wala.util.strings.Atom;
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2011-05-02 22:11:27 +00:00
|
|
|
/**
|
|
|
|
* Specialization of {@link AstTranslator} for JavaScript.
|
|
|
|
*
|
|
|
|
*/
|
2007-02-02 17:25:09 +00:00
|
|
|
public class JSAstTranslator extends AstTranslator {
|
2009-05-04 14:11:31 +00:00
|
|
|
private final static boolean DEBUG = false;
|
2007-02-02 17:25:09 +00:00
|
|
|
|
|
|
|
public JSAstTranslator(JavaScriptLoader loader) {
|
|
|
|
super(loader);
|
|
|
|
}
|
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
private boolean isPrologueScript(WalkContext context) {
|
|
|
|
return JavaScriptLoader.bootstrapFileNames.contains( context.getModule().getName() );
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-04 13:05:48 +00:00
|
|
|
protected boolean useDefaultInitValues() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2011-04-26 18:44:49 +00:00
|
|
|
protected boolean hasImplicitGlobals() {
|
2007-02-02 17:25:09 +00:00
|
|
|
return true;
|
|
|
|
}
|
2011-04-26 18:44:49 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2011-04-26 18:44:49 +00:00
|
|
|
protected boolean treatGlobalsAsLexicallyScoped() {
|
2011-05-23 16:27:07 +00:00
|
|
|
return false;
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
2012-02-17 20:14:26 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
protected TypeReference defaultCatchType() {
|
|
|
|
return JavaScriptTypes.Root;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
protected TypeReference makeType(CAstType type) {
|
2014-03-16 22:05:49 +00:00
|
|
|
assert "Any".equals(type.getName());
|
|
|
|
return JavaScriptTypes.Root;
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2013-10-16 21:37:53 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
protected boolean ignoreName(String name) {
|
|
|
|
return super.ignoreName(name) || name.endsWith(" temp");
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2014-02-09 02:34:34 +00:00
|
|
|
@Override
|
|
|
|
protected String[] makeNameMap(CAstEntity n, Set<Scope> scopes, SSAInstruction[] insts) {
|
|
|
|
String[] names = super.makeNameMap(n, scopes, insts);
|
|
|
|
for(SSAInstruction inst : insts) {
|
|
|
|
if (inst instanceof PrototypeLookup) {
|
|
|
|
if (names[ inst.getUse(0)] != null) {
|
|
|
|
names[ inst.getDef() ] = names[ inst.getUse(0) ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return names;
|
|
|
|
}
|
|
|
|
|
2011-05-02 22:11:27 +00:00
|
|
|
/**
|
|
|
|
* generate an instruction that checks if readVn is undefined and throws an exception if it isn't
|
|
|
|
*/
|
2009-01-30 16:33:22 +00:00
|
|
|
private void addDefinedCheck(CAstNode n, WalkContext context, int readVn) {
|
2009-01-27 17:40:11 +00:00
|
|
|
context.cfg().addPreNode(n);
|
2011-04-13 10:56:36 +00:00
|
|
|
context.cfg().addInstruction(((JSInstructionFactory)insts).CheckReference(context.cfg().getCurrentInstruction(), readVn));
|
2009-01-27 17:40:11 +00:00
|
|
|
CAstNode target = context.getControlFlow().getTarget(n, JavaScriptTypes.ReferenceError);
|
2010-04-28 19:38:28 +00:00
|
|
|
if (target != null) {
|
|
|
|
context.cfg().addPreEdge(n, target, true);
|
|
|
|
} else {
|
|
|
|
context.cfg().addPreEdgeToExit(n, true);
|
|
|
|
}
|
2011-04-26 18:44:49 +00:00
|
|
|
context.cfg().newBlock(true);
|
2009-01-30 16:33:22 +00:00
|
|
|
}
|
2011-04-26 18:44:49 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2014-03-16 22:05:49 +00:00
|
|
|
protected int doLexicallyScopedRead(CAstNode n, WalkContext context, String name, TypeReference type) {
|
|
|
|
int readVn = super.doLexicallyScopedRead(n, context, name, type);
|
2011-05-02 22:11:27 +00:00
|
|
|
// should get an exception if name is undefined
|
2009-01-30 16:33:22 +00:00
|
|
|
addDefinedCheck(n, context, readVn);
|
2009-01-27 17:40:11 +00:00
|
|
|
return readVn;
|
|
|
|
}
|
2011-04-26 18:44:49 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2014-03-16 22:05:49 +00:00
|
|
|
protected int doGlobalRead(CAstNode n, WalkContext context, String name, TypeReference type) {
|
|
|
|
int readVn = super.doGlobalRead(n, context, name, type);
|
2011-05-02 22:11:27 +00:00
|
|
|
// add a check if name is undefined, unless we're reading the value 'undefined'
|
2015-02-26 14:34:03 +00:00
|
|
|
if (n != null && !("undefined".equals(name) || "$$undefined".equals(name))) {
|
2009-01-30 16:33:22 +00:00
|
|
|
addDefinedCheck(n, context, readVn);
|
|
|
|
}
|
|
|
|
return readVn;
|
|
|
|
}
|
2011-04-26 18:44:49 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2011-04-04 15:23:58 +00:00
|
|
|
protected boolean defineType(CAstEntity type, WalkContext wc) {
|
2011-04-26 18:44:49 +00:00
|
|
|
Assertions.UNREACHABLE("JavaScript doesn't have types. I suggest you look elsewhere for your amusement.");
|
|
|
|
return false;
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
protected void defineField(CAstEntity topEntity, WalkContext wc, CAstEntity n) {
|
2012-03-01 02:45:51 +00:00
|
|
|
Assertions.UNREACHABLE("JavaScript doesn't have fields");
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
protected String composeEntityName(WalkContext parent, CAstEntity f) {
|
2011-04-26 18:44:49 +00:00
|
|
|
if (f.getKind() == CAstEntity.SCRIPT_ENTITY)
|
|
|
|
return f.getName();
|
|
|
|
else
|
|
|
|
return parent.getName() + "/" + f.getName();
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
protected void declareFunction(CAstEntity N, WalkContext context) {
|
|
|
|
String fnName = composeEntityName(context, N);
|
|
|
|
if (N.getKind() == CAstEntity.SCRIPT_ENTITY) {
|
2012-01-27 20:15:33 +00:00
|
|
|
((JavaScriptLoader) loader).defineScriptType("L" + fnName, N.getPosition(), N, context);
|
2007-02-02 17:25:09 +00:00
|
|
|
} else if (N.getKind() == CAstEntity.FUNCTION_ENTITY) {
|
2012-01-27 20:15:33 +00:00
|
|
|
((JavaScriptLoader) loader).defineFunctionType("L" + fnName, N.getPosition(), N, context);
|
2007-02-02 17:25:09 +00:00
|
|
|
} else {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2017-02-23 15:10:39 +00:00
|
|
|
protected void defineFunction(CAstEntity N, WalkContext definingContext, AbstractCFG<SSAInstruction, ? extends IBasicBlock<SSAInstruction>> cfg, SymbolTable symtab,
|
|
|
|
boolean hasCatchBlock, Map<IBasicBlock<SSAInstruction>,TypeReference[]> caughtTypes, boolean hasMonitorOp, AstLexicalInformation LI,
|
2011-04-26 18:44:49 +00:00
|
|
|
DebuggingInformation debugInfo) {
|
2009-04-09 20:31:14 +00:00
|
|
|
if (DEBUG)
|
|
|
|
System.err.println(("\n\nAdding code for " + N));
|
2007-02-02 17:25:09 +00:00
|
|
|
String fnName = composeEntityName(definingContext, N);
|
2011-04-26 18:44:49 +00:00
|
|
|
|
2009-04-09 20:31:14 +00:00
|
|
|
if (DEBUG)
|
|
|
|
System.err.println(cfg);
|
2011-05-23 16:27:07 +00:00
|
|
|
|
2011-04-26 18:44:49 +00:00
|
|
|
((JavaScriptLoader) loader).defineCodeBodyCode("L" + fnName, cfg, symtab, hasCatchBlock, caughtTypes, hasMonitorOp, LI,
|
|
|
|
debugInfo);
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
protected void doThrow(WalkContext context, int exception) {
|
2011-04-13 10:56:36 +00:00
|
|
|
context.cfg().addInstruction(insts.ThrowInstruction(context.cfg().getCurrentInstruction(), exception));
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
2011-04-26 18:44:49 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
protected void doCall(WalkContext context, CAstNode call, int result, int exception, CAstNode name, int receiver, int[] arguments) {
|
2012-03-01 02:45:51 +00:00
|
|
|
MethodReference ref =
|
|
|
|
name.getValue().equals("ctor") ? JavaScriptMethods.ctorReference
|
|
|
|
: name.getValue().equals("dispatch") ? JavaScriptMethods.dispatchReference
|
|
|
|
: AstMethodReference.fnReference(JavaScriptTypes.CodeBody);
|
2011-04-26 18:44:49 +00:00
|
|
|
|
2007-02-02 17:25:09 +00:00
|
|
|
context.cfg().addInstruction(
|
2014-04-09 14:29:47 +00:00
|
|
|
((JSInstructionFactory) insts).Invoke(context.cfg().getCurrentInstruction(), receiver, result, arguments, exception,
|
2012-03-01 02:45:51 +00:00
|
|
|
new JSCallSiteReference(ref, context.cfg().getCurrentInstruction())));
|
2007-02-02 17:25:09 +00:00
|
|
|
|
|
|
|
context.cfg().addPreNode(call, context.getUnwindState());
|
|
|
|
|
2011-05-02 22:11:27 +00:00
|
|
|
// this new block is for the normal termination case
|
2011-04-26 18:44:49 +00:00
|
|
|
context.cfg().newBlock(true);
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2011-05-02 22:11:27 +00:00
|
|
|
// exceptional case: flow to target given in CAst, or if null, the exit node
|
2007-02-02 17:25:09 +00:00
|
|
|
if (context.getControlFlow().getTarget(call, null) != null)
|
|
|
|
context.cfg().addPreEdge(call, context.getControlFlow().getTarget(call, null), true);
|
|
|
|
else
|
2011-04-26 18:44:49 +00:00
|
|
|
context.cfg().addPreEdgeToExit(call, true);
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
protected void doNewObject(WalkContext context, CAstNode newNode, int result, Object type, int[] arguments) {
|
2009-04-30 13:16:52 +00:00
|
|
|
assert arguments == null;
|
2011-04-26 18:44:49 +00:00
|
|
|
TypeReference typeRef = TypeReference.findOrCreate(JavaScriptTypes.jsLoader, TypeName.string2TypeName("L" + type));
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2014-04-09 11:34:16 +00:00
|
|
|
context.cfg().addInstruction(insts.NewInstruction(context.cfg().getCurrentInstruction(), result,
|
|
|
|
NewSiteReference.make(context.cfg().getCurrentInstruction(), typeRef)));
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2009-01-30 16:33:22 +00:00
|
|
|
protected void doMaterializeFunction(CAstNode n, WalkContext context, int result, int exception, CAstEntity fn) {
|
2011-04-26 18:44:49 +00:00
|
|
|
int nm = context.currentScope().getConstantValue("L" + composeEntityName(context, fn));
|
2011-05-02 22:11:27 +00:00
|
|
|
// "Function" is the name we use to model the constructor of function values
|
2014-03-16 22:05:49 +00:00
|
|
|
int tmp = super.doGlobalRead(n, context, "Function", JavaScriptTypes.Function);
|
2007-02-02 17:25:09 +00:00
|
|
|
context.cfg().addInstruction(
|
2011-04-13 10:56:36 +00:00
|
|
|
((JSInstructionFactory)insts).Invoke(context.cfg().getCurrentInstruction(), tmp, result, new int[]{ nm }, exception,
|
2014-04-09 11:34:16 +00:00
|
|
|
new JSCallSiteReference(JavaScriptMethods.ctorReference, context.cfg().getCurrentInstruction())));
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-07-12 22:50:46 +00:00
|
|
|
public void doArrayRead(WalkContext context, int result, int arrayValue, CAstNode arrayRef, int[] dimValues) {
|
2011-04-26 18:44:49 +00:00
|
|
|
Assertions.UNREACHABLE("JSAstTranslator.doArrayRead() called!");
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-07-12 22:50:46 +00:00
|
|
|
public void doArrayWrite(WalkContext context, int arrayValue, CAstNode arrayRef, int[] dimValues, int rval) {
|
2011-04-26 18:44:49 +00:00
|
|
|
Assertions.UNREACHABLE("JSAstTranslator.doArrayWrite() called!");
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2011-05-02 22:11:27 +00:00
|
|
|
protected void doFieldRead(WalkContext context, int result, int receiver, CAstNode elt, CAstNode readNode) {
|
2008-11-06 18:00:11 +00:00
|
|
|
this.visit(elt, context, this);
|
2007-02-02 17:25:09 +00:00
|
|
|
int x = context.currentScope().allocateTempValue();
|
|
|
|
|
2011-04-13 10:56:36 +00:00
|
|
|
context.cfg().addInstruction(((JSInstructionFactory)insts).AssignInstruction(context.cfg().getCurrentInstruction(), x, receiver));
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2014-04-09 14:29:47 +00:00
|
|
|
context.cfg().addInstruction(((JSInstructionFactory) insts).PrototypeLookup(context.cfg().getCurrentInstruction(), x, x));
|
2012-03-01 02:45:51 +00:00
|
|
|
|
2011-04-26 18:44:49 +00:00
|
|
|
if (elt.getKind() == CAstNode.CONSTANT && elt.getValue() instanceof String) {
|
|
|
|
String field = (String) elt.getValue();
|
2010-09-10 22:33:47 +00:00
|
|
|
// symtab needs to have this value
|
|
|
|
context.currentScope().getConstantValue(field);
|
2007-02-02 17:25:09 +00:00
|
|
|
context.cfg().addInstruction(
|
2011-04-13 10:56:36 +00:00
|
|
|
((JSInstructionFactory)insts).GetInstruction(context.cfg().getCurrentInstruction(), result, x, field));
|
2007-02-02 17:25:09 +00:00
|
|
|
} else {
|
2014-04-09 14:29:47 +00:00
|
|
|
context.cfg().addInstruction(((JSInstructionFactory) insts).PropertyRead(context.cfg().getCurrentInstruction(), result, x, context.getValue(elt)));
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
2011-04-26 18:44:49 +00:00
|
|
|
|
2014-07-08 18:44:06 +00:00
|
|
|
// generate code to handle read of property from null or undefined
|
|
|
|
context.cfg().addPreNode(readNode, context.getUnwindState());
|
2011-04-13 16:27:15 +00:00
|
|
|
|
2014-07-08 18:44:06 +00:00
|
|
|
context.cfg().newBlock(true);
|
2011-04-13 16:27:15 +00:00
|
|
|
|
2014-07-08 18:44:06 +00:00
|
|
|
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);
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
2011-04-26 18:44:49 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
protected void doFieldWrite(WalkContext context, int receiver, CAstNode elt, CAstNode parent, int rval) {
|
2008-11-06 18:00:11 +00:00
|
|
|
this.visit(elt, context, this);
|
2011-04-26 18:44:49 +00:00
|
|
|
if (elt.getKind() == CAstNode.CONSTANT && elt.getValue() instanceof String) {
|
|
|
|
String field = (String) elt.getValue();
|
2012-03-01 02:45:51 +00:00
|
|
|
if (isPrologueScript(context) && "__proto__".equals(field)) {
|
2014-04-09 14:29:47 +00:00
|
|
|
context.cfg().addInstruction(((JSInstructionFactory) insts).SetPrototype(context.cfg().getCurrentInstruction(), receiver, rval));
|
2014-04-09 15:15:08 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
2012-03-01 02:45:51 +00:00
|
|
|
} else {
|
|
|
|
context.currentScope().getConstantValue(field);
|
2014-04-09 14:29:47 +00:00
|
|
|
SSAPutInstruction put = ((JSInstructionFactory) insts).PutInstruction(context.cfg().getCurrentInstruction(), receiver, rval, field);
|
2012-03-01 02:45:51 +00:00
|
|
|
try {
|
|
|
|
assert field.equals(put.getDeclaredField().getName().toUnicodeString());
|
|
|
|
} catch (UTFDataFormatException e) {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
context.cfg().addInstruction(put);
|
2010-09-14 20:29:05 +00:00
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
} else {
|
2014-07-08 18:44:06 +00:00
|
|
|
*/
|
2014-04-09 14:29:47 +00:00
|
|
|
context.cfg().addInstruction(((JSInstructionFactory) insts).PropertyWrite(context.cfg().getCurrentInstruction(), receiver, context.getValue(elt), rval));
|
2014-07-08 18:44:06 +00:00
|
|
|
context.cfg().addPreNode(parent, context.getUnwindState());
|
|
|
|
|
|
|
|
// generate code to handle read of property from null or undefined
|
|
|
|
context.cfg().newBlock(true);
|
|
|
|
|
|
|
|
if (context.getControlFlow().getTarget(parent, JavaScriptTypes.TypeError) != null)
|
|
|
|
context.cfg().addPreEdge(parent, context.getControlFlow().getTarget(parent, JavaScriptTypes.TypeError), true);
|
|
|
|
else
|
|
|
|
context.cfg().addPreEdgeToExit(parent, true);
|
|
|
|
// }
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2011-04-26 18:44:49 +00:00
|
|
|
private void doPrimitiveNew(WalkContext context, int resultVal, String typeName) {
|
2007-04-19 13:53:31 +00:00
|
|
|
doNewObject(context, null, resultVal, typeName + "Object", null);
|
2011-05-02 22:11:27 +00:00
|
|
|
// set the class property of the new object
|
2007-04-19 13:53:31 +00:00
|
|
|
int rval = context.currentScope().getConstantValue(typeName);
|
2010-09-10 22:33:47 +00:00
|
|
|
context.currentScope().getConstantValue("class");
|
2007-04-19 13:53:31 +00:00
|
|
|
context.cfg().addInstruction(
|
2011-04-13 10:56:36 +00:00
|
|
|
((JSInstructionFactory)insts).PutInstruction(context.cfg().getCurrentInstruction(), resultVal, rval, "class"));
|
2007-04-19 13:53:31 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
protected void doPrimitive(int resultVal, WalkContext context, CAstNode primitiveCall) {
|
|
|
|
try {
|
2011-04-26 18:44:49 +00:00
|
|
|
String name = (String) primitiveCall.getChild(0).getValue();
|
2007-02-02 17:25:09 +00:00
|
|
|
if (name.equals("GlobalNaN")) {
|
|
|
|
context.cfg().addInstruction(
|
2011-04-13 10:56:36 +00:00
|
|
|
((JSInstructionFactory)insts).AssignInstruction(context.cfg().getCurrentInstruction(),
|
2014-04-09 11:34:16 +00:00
|
|
|
resultVal, context.currentScope().getConstantValue(new Float(Float.NaN))));
|
2007-02-02 17:25:09 +00:00
|
|
|
} else if (name.equals("GlobalInfinity")) {
|
|
|
|
context.cfg().addInstruction(
|
2011-04-13 10:56:36 +00:00
|
|
|
((JSInstructionFactory)insts).AssignInstruction(context.cfg().getCurrentInstruction(),
|
2014-04-09 11:34:16 +00:00
|
|
|
resultVal, context.currentScope().getConstantValue(new Float(Float.POSITIVE_INFINITY))));
|
2007-02-02 17:25:09 +00:00
|
|
|
} else if (name.equals("MathE")) {
|
|
|
|
context.cfg().addInstruction(
|
2011-04-13 10:56:36 +00:00
|
|
|
((JSInstructionFactory)insts).AssignInstruction(context.cfg().getCurrentInstruction(),
|
2014-04-09 11:34:16 +00:00
|
|
|
resultVal, context.currentScope().getConstantValue(new Double(Math.E))));
|
2007-02-02 17:25:09 +00:00
|
|
|
} else if (name.equals("MathPI")) {
|
|
|
|
context.cfg().addInstruction(
|
2011-04-13 10:56:36 +00:00
|
|
|
((JSInstructionFactory)insts).AssignInstruction(context.cfg().getCurrentInstruction(),
|
2014-04-09 11:34:16 +00:00
|
|
|
resultVal, context.currentScope().getConstantValue(new Double(Math.PI))));
|
2007-02-02 17:25:09 +00:00
|
|
|
} else if (name.equals("MathSQRT1_2")) {
|
|
|
|
context.cfg().addInstruction(
|
2011-04-13 10:56:36 +00:00
|
|
|
((JSInstructionFactory)insts).AssignInstruction(context.cfg().getCurrentInstruction(),
|
2014-04-09 11:34:16 +00:00
|
|
|
resultVal, context.currentScope().getConstantValue(new Double(Math.sqrt(.5)))));
|
2007-02-02 17:25:09 +00:00
|
|
|
} else if (name.equals("MathSQRT2")) {
|
|
|
|
context.cfg().addInstruction(
|
2011-04-13 10:56:36 +00:00
|
|
|
((JSInstructionFactory)insts).AssignInstruction(context.cfg().getCurrentInstruction(),
|
2014-04-09 11:34:16 +00:00
|
|
|
resultVal, context.currentScope().getConstantValue(new Double(Math.sqrt(2)))));
|
2007-02-02 17:25:09 +00:00
|
|
|
} else if (name.equals("MathLN2")) {
|
|
|
|
context.cfg().addInstruction(
|
2011-04-13 10:56:36 +00:00
|
|
|
((JSInstructionFactory)insts).AssignInstruction(context.cfg().getCurrentInstruction(),
|
2014-04-09 11:34:16 +00:00
|
|
|
resultVal, context.currentScope().getConstantValue(new Double(Math.log(2)))));
|
2007-02-02 17:25:09 +00:00
|
|
|
} else if (name.equals("MathLN10")) {
|
|
|
|
context.cfg().addInstruction(
|
2011-04-13 10:56:36 +00:00
|
|
|
((JSInstructionFactory)insts).AssignInstruction(context.cfg().getCurrentInstruction(),
|
2014-04-09 11:34:16 +00:00
|
|
|
resultVal, context.currentScope().getConstantValue(new Double(Math.log(10)))));
|
2007-02-02 17:25:09 +00:00
|
|
|
} else if (name.equals("NewObject")) {
|
2011-04-26 18:44:49 +00:00
|
|
|
doNewObject(context, null, resultVal, "Object", null);
|
2007-02-02 17:25:09 +00:00
|
|
|
|
|
|
|
} else if (name.equals("NewArray")) {
|
2011-04-26 18:44:49 +00:00
|
|
|
doNewObject(context, null, resultVal, "Array", null);
|
2007-02-02 17:25:09 +00:00
|
|
|
|
|
|
|
} else if (name.equals("NewString")) {
|
2011-04-26 18:44:49 +00:00
|
|
|
doPrimitiveNew(context, resultVal, "String");
|
2007-02-02 17:25:09 +00:00
|
|
|
|
|
|
|
} else if (name.equals("NewNumber")) {
|
2011-04-26 18:44:49 +00:00
|
|
|
doPrimitiveNew(context, resultVal, "Number");
|
2007-02-02 17:25:09 +00:00
|
|
|
|
|
|
|
} else if (name.equals("NewRegExp")) {
|
2011-04-26 18:44:49 +00:00
|
|
|
doPrimitiveNew(context, resultVal, "RegExp");
|
2007-02-02 17:25:09 +00:00
|
|
|
|
|
|
|
} else if (name.equals("NewFunction")) {
|
2011-04-26 18:44:49 +00:00
|
|
|
doNewObject(context, null, resultVal, "Function", null);
|
2007-02-02 17:25:09 +00:00
|
|
|
|
|
|
|
} else if (name.equals("NewUndefined")) {
|
2011-04-26 18:44:49 +00:00
|
|
|
doNewObject(context, null, resultVal, "Undefined", null);
|
2007-02-02 17:25:09 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
context.cfg().addInstruction(
|
2011-04-13 10:56:36 +00:00
|
|
|
((JSInstructionFactory)insts).AssignInstruction(context.cfg().getCurrentInstruction(),
|
2014-04-09 11:34:16 +00:00
|
|
|
resultVal, context.currentScope().getConstantValue( null )));
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
} catch (ClassCastException e) {
|
2017-03-18 04:38:59 +00:00
|
|
|
throw new RuntimeException("Cannot translate primitive " + primitiveCall.getChild(0).getValue(), e);
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2011-04-26 18:44:49 +00:00
|
|
|
protected void doIsFieldDefined(WalkContext context, int result, int ref, CAstNode f) {
|
2007-04-19 13:53:31 +00:00
|
|
|
if (f.getKind() == CAstNode.CONSTANT && f.getValue() instanceof String) {
|
|
|
|
String field = (String) f.getValue();
|
|
|
|
|
2014-06-26 15:51:26 +00:00
|
|
|
FieldReference fieldRef = FieldReference.findOrCreate(JavaScriptTypes.Root, Atom.findOrCreateUnicodeAtom(field),
|
2011-04-26 18:44:49 +00:00
|
|
|
JavaScriptTypes.Root);
|
|
|
|
|
2014-07-28 15:09:02 +00:00
|
|
|
context.cfg().addInstruction(((JSInstructionFactory) insts).IsDefinedInstruction(context.cfg().getCurrentInstruction(), result, ref, fieldRef));
|
2007-04-19 13:53:31 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
2014-04-09 14:29:47 +00:00
|
|
|
context.cfg().addInstruction(((JSInstructionFactory) insts).IsDefinedInstruction(context.cfg().getCurrentInstruction(), result, ref, context.getValue(f)));
|
2007-04-19 13:53:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-01-27 20:15:33 +00:00
|
|
|
protected boolean visitInstanceOf(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2014-06-26 15:51:26 +00:00
|
|
|
WalkContext context = c;
|
2008-12-16 14:54:09 +00:00
|
|
|
int result = context.currentScope().allocateTempValue();
|
2012-01-27 20:15:33 +00:00
|
|
|
context.setValue(n, result);
|
2008-12-16 14:54:09 +00:00
|
|
|
return false;
|
|
|
|
}
|
2011-04-26 18:44:49 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-01-27 20:15:33 +00:00
|
|
|
protected void leaveInstanceOf(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
|
2014-06-26 15:51:26 +00:00
|
|
|
WalkContext context = c;
|
2012-01-27 20:15:33 +00:00
|
|
|
int result = context.getValue(n);
|
2011-04-26 18:44:49 +00:00
|
|
|
|
2008-12-16 14:54:09 +00:00
|
|
|
visit(n.getChild(0), context, visitor);
|
2012-01-27 20:15:33 +00:00
|
|
|
int value = context.getValue(n.getChild(0));
|
2008-12-16 14:54:09 +00:00
|
|
|
|
|
|
|
visit(n.getChild(1), context, visitor);
|
2012-01-27 20:15:33 +00:00
|
|
|
int type = context.getValue(n.getChild(1));
|
2008-12-16 14:54:09 +00:00
|
|
|
|
2011-04-13 10:56:36 +00:00
|
|
|
context.cfg().addInstruction(new JavaScriptInstanceOf(context.cfg().getCurrentInstruction(), result, value, type));
|
2011-04-26 18:44:49 +00:00
|
|
|
}
|
2008-12-16 14:54:09 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-06-28 14:32:15 +00:00
|
|
|
protected void doPrologue(WalkContext context) {
|
|
|
|
super.doPrologue(context);
|
2011-05-02 22:11:27 +00:00
|
|
|
|
2007-06-28 14:32:15 +00:00
|
|
|
int tempVal = context.currentScope().allocateTempValue();
|
|
|
|
doNewObject(context, null, tempVal, "Array", null);
|
2014-03-16 22:05:49 +00:00
|
|
|
CAstSymbol args = new CAstSymbolImpl("arguments", Any);
|
2007-06-28 14:32:15 +00:00
|
|
|
context.currentScope().declare(args, tempVal);
|
2014-04-09 14:29:47 +00:00
|
|
|
//context.cfg().addInstruction(((JSInstructionFactory)insts).PutInstruction(context.cfg().getCurrentInstruction(), 1, tempVal, "arguments"));
|
2007-06-28 14:32:15 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2014-03-16 22:05:49 +00:00
|
|
|
protected boolean doVisit(CAstNode n, WalkContext context, CAstVisitor<WalkContext> visitor) {
|
2007-02-02 17:25:09 +00:00
|
|
|
switch (n.getKind()) {
|
|
|
|
case CAstNode.TYPE_OF: {
|
|
|
|
int result = context.currentScope().allocateTempValue();
|
|
|
|
|
2008-11-06 18:00:11 +00:00
|
|
|
this.visit(n.getChild(0), context, this);
|
2012-01-27 20:15:33 +00:00
|
|
|
int ref = context.getValue(n.getChild(0));
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2014-04-09 11:34:16 +00:00
|
|
|
context.cfg().addInstruction(((JSInstructionFactory)insts).TypeOfInstruction(context.cfg().getCurrentInstruction(), result, ref));
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2012-01-27 20:15:33 +00:00
|
|
|
context.setValue(n, result);
|
2007-02-02 17:25:09 +00:00
|
|
|
return true;
|
|
|
|
}
|
2011-04-26 18:44:49 +00:00
|
|
|
|
2009-01-27 17:40:11 +00:00
|
|
|
case JavaScriptCAstNode.ENTER_WITH:
|
|
|
|
case JavaScriptCAstNode.EXIT_WITH: {
|
|
|
|
|
|
|
|
this.visit(n.getChild(0), context, this);
|
2012-01-27 20:15:33 +00:00
|
|
|
int ref = context.getValue(n.getChild(0));
|
2009-01-27 17:40:11 +00:00
|
|
|
|
2014-04-09 11:34:16 +00:00
|
|
|
context.cfg().addInstruction(((JSInstructionFactory)insts).WithRegion(context.cfg().getCurrentInstruction(), ref,
|
|
|
|
n.getKind() == JavaScriptCAstNode.ENTER_WITH));
|
2009-01-27 17:40:11 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
default: {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-16 22:05:49 +00:00
|
|
|
public static final CAstType Any = new CAstType() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String getName() {
|
|
|
|
return "Any";
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-01-11 13:04:37 +00:00
|
|
|
public Collection<CAstType> getSupertypes() {
|
2014-03-16 22:05:49 +00:00
|
|
|
return Collections.EMPTY_SET;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected CAstType topType() {
|
|
|
|
return Any;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected CAstType exceptionType() {
|
|
|
|
return Any;
|
|
|
|
}
|
|
|
|
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|