/******************************************************************************* * Copyright (c) 2013 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.html; import com.ibm.wala.cast.ir.translator.TranslatorToIR; import com.ibm.wala.cast.js.loader.JavaScriptLoader; import com.ibm.wala.cast.js.loader.JavaScriptLoaderFactory; import com.ibm.wala.cast.js.ssa.JSInstructionFactory; import com.ibm.wala.cast.js.translator.JSAstTranslator; import com.ibm.wala.cast.js.translator.JavaScriptTranslatorFactory; import com.ibm.wala.cast.js.types.JavaScriptTypes; import com.ibm.wala.cast.tree.CAst; import com.ibm.wala.cast.tree.CAstEntity; import com.ibm.wala.cast.tree.CAstNode; import com.ibm.wala.cast.tree.impl.CAstImpl; import com.ibm.wala.cast.tree.impl.CAstOperator; import com.ibm.wala.cast.tree.rewrite.CAstRewriterFactory; import com.ibm.wala.cast.tree.visit.CAstVisitor; import com.ibm.wala.classLoader.IClassLoader; import com.ibm.wala.ipa.cha.IClassHierarchy; import com.ibm.wala.types.TypeReference; public class WebPageLoaderFactory extends JavaScriptLoaderFactory { public WebPageLoaderFactory(JavaScriptTranslatorFactory factory) { super(factory); } public WebPageLoaderFactory(JavaScriptTranslatorFactory factory, CAstRewriterFactory preprocessor) { super(factory, preprocessor); } @Override protected IClassLoader makeTheLoader(IClassHierarchy cha) { return new JavaScriptLoader( cha, translatorFactory, preprocessor ) { @Override protected TranslatorToIR initTranslator() { return new JSAstTranslator(this) { private final CAst Ast = new CAstImpl(); private boolean isNestedWithinScriptBody(WalkContext context) { return isScriptBody(context) || context.getName().contains("__WINDOW_MAIN__"); } private boolean isScriptBody(WalkContext context) { return context.top().getName().equals( "__WINDOW_MAIN__" ); } @Override protected int doGlobalRead(CAstNode n, WalkContext context, String name, TypeReference type) { int result = context.currentScope().allocateTempValue(); if (isNestedWithinScriptBody(context) && ! "$$undefined".equals(name) && !"window".equals(name) && !name.startsWith("$$destructure")) { // check if field is defined on 'window' int windowVal = isScriptBody(context)? super.doLocalRead(context, "this", JavaScriptTypes.Root): super.doGlobalRead(n, context, "window", type); int isDefined = context.currentScope().allocateTempValue(); context.currentScope().getConstantValue(name); doIsFieldDefined(context, isDefined, windowVal, Ast.makeConstant(name)); context.cfg().addInstruction( insts.ConditionalBranchInstruction(context.cfg().getCurrentInstruction(), translateConditionOpcode(CAstOperator.OP_NE), null, isDefined, context.currentScope().getConstantValue(new Integer(0)), -1)); PreBasicBlock srcB = context.cfg().getCurrentBlock(); // field lookup of value context.cfg().newBlock(true); context.cfg().addInstruction(((JSInstructionFactory) insts).GetInstruction(context.cfg().getCurrentInstruction(), result, windowVal, name)); context.cfg().newBlock(true); context.cfg().addInstruction(insts.GotoInstruction(context.cfg().getCurrentInstruction(), -1)); PreBasicBlock trueB = context.cfg().getCurrentBlock(); // read global context.cfg().newBlock(false); PreBasicBlock falseB = context.cfg().getCurrentBlock(); int sr = super.doGlobalRead(n, context, name, type); context.cfg().addInstruction(((JSInstructionFactory) insts).AssignInstruction(context.cfg().getCurrentInstruction(), result, sr)); // end context.cfg().newBlock(true); context.cfg().addEdge(trueB, context.cfg().getCurrentBlock()); context.cfg().addEdge(srcB, falseB); return result; } else { return super.doGlobalRead(n, context, name, type); } } @Override protected void doLocalWrite(WalkContext context, String nm, TypeReference type, int rval) { if (isNestedWithinScriptBody(context) && ! "$$undefined".equals(nm) && !"window".equals(nm) && !nm.startsWith("$$destructure")) { int windowVal = super.doLocalRead(context, "this", type); context.currentScope().getConstantValue(nm); context.cfg().addInstruction(((JSInstructionFactory) insts).PutInstruction(context.cfg().getCurrentInstruction(), windowVal, rval, nm)); } super.doLocalWrite(context, nm, type, rval); } @Override protected void leaveFunctionStmt(CAstNode n, WalkContext context, CAstVisitor<WalkContext> visitor) { super.leaveFunctionStmt(n, context, visitor); if (isScriptBody(context)) { CAstEntity fn = (CAstEntity) n.getChild(0).getValue(); int fnValue = context.currentScope().lookup(fn.getName()).valueNumber(); assert fnValue > 0; int windowVal = super.doLocalRead(context, "this", JavaScriptTypes.Function); context.cfg().addInstruction(((JSInstructionFactory) insts).PutInstruction(context.cfg().getCurrentInstruction(), windowVal, fnValue, fn.getName())); } } }; } }; } }