#include "AST.h" #include "CodeContext.h" #include "code.h" #include "lgMacro.h" #include "decls.h" #include "code-assign.h" #include "code-util.h" #include "types.h" const string assignPrefix(AssignKind kind, bool isStatic) { static char *assignMacros[][2] = { {"", ""}, {"PL", "SPL"}, {"PG", "SPG"} }; return assignMacros[kind][isStatic]; } const string assignSuffix(AssignType atype, bool isLocal) { static char *assignMacros[][2] = { {"", ""}, {"", "_unknown"}, {"", "_jboolean"}, {"", "_jbyte"}, {"", "_jchar"}, {"", "_jdouble"}, {"", "_jfloat"}, {"", "_jint"}, {"", "_jlong"}, {"", "_jshort"}, {"", "_lp"}, {"", "_gp"}, {"", "_bulk"} }; return assignMacros[atype][!isLocal]; } const string assignMacro(AssignKind kind, AssignType atype, bool isStatic, bool isLocal) { return assignPrefix(kind, isStatic) + lgMacro("ASSIGN", isLocal) + assignSuffix(atype, isLocal); } AssignKind assignKind(const TypeNode *type) { if (type->isReference()) if (type->isLocal()) return assignLocal; else return assignGlobal; else return assignNormal; } AssignType assignType(const TypeNode *type) { switch(type->kind()) { case Common::ByteKind: return assignByte; case Common::ShortKind: return assignShort; case Common::CharKind: return assignChar; case Common::IntKind: return assignInt; case Common::LongKind: return assignLong; case Common::FloatKind: return assignFloat; case Common::DoubleKind: return assignDouble; case Common::BoolKind: return assignBoolean; case Common::NullKind: if (type->isLocal()) return assignLP; else return assignGP; case Common::VoidKind: fatal_error("should never reach here"); case Common::ArrayKind: return assignBulk; case Common::ImmutableKind: return assignBulk; case Common::ClassKind: case Common::InterfaceKind: { if (type->isReference()) { if (type->isLocal()) return assignLP; else return assignGP; } else return assignUnknown; } case Common::ArrayInitializerKind: /* uh oh */ case Common::MethodKind: /* Uh oh */ return assignUnknown; } return assignUnknown; } const string makeAssign(const string &lvalue, const string &value, const bool isLocal, AssignKind kind, AssignType type, bool isStatic) { return assignMacro(kind, type, isStatic, isLocal) + '(' + lvalue + "," + value + ")"; } void TreeNode::receiveAssign(ostream &, const string &, const string &, AssignKind, const TypeNode *) { undefined("receiveAssign"); } void ObjectFieldAccessNode::receiveAssign(ostream &out, const string &lvalue, const string &value, AssignKind kind, const TypeNode *type) { const bool isStatic = (decl()->modifiers() & Static) != 0; const AssignType atype = assignType(type); accessedObjectType()->fencePreWrite( out ); out << makeAssign(lvalue, value, isLocalLvalue(), kind, atype, isStatic) << ';' << endCline; accessedObjectType()->fencePostWrite( out ); } void TypeFieldAccessNode::receiveAssign(ostream &out, const string &lvalue, const string &value, AssignKind kind, const TypeNode *type) { const AssignType atype = assignType(type); #ifdef PR_371_has_been_fixed // !!!: enable this code once PR #371 gets fixed out << fencePreWrite; #endif out << makeAssign(lvalue, value, isLocalLvalue(), kind, atype, true) << ';' << endCline; #ifdef PR_371_has_been_fixed // !!!: enable this code once PR #371 gets fixed out << fencePostWrite; #endif } // True for non-static ObjectFieldAccessNode's whose object is immutable bool TreeNode::isFieldOfImmutable() const { return false; } // Immutables can have global pointers embedded in them when they are passed // between nodes; this routine recursively searches for them inside an // immutable type and returns a list of the names of each global pointer // field. The argument "myname" should be the name of the variable whose type // is under suspicion--the field names of the global pointers will be appended // to this and returned. llist *TypeNode::findGptrs(string myname, bool toplevel_p = true) { llist *gpnames = NULL; static llist *markList = NULL; if (toplevel_p) { free_all(markList); markList = NULL; } if (isReference() && !isLocal()) { gpnames = cons(myname); } else if (isTitaniumArrayType() && !isLocal()) { //gpnames = cons(myname + ".A"); gpnames = cons(myname + ".ancestor"); // DOB: use ancestor, which always points to start of mem block } else if (kind() == ImmutableKind) { if (find(this, markList)) return gpnames; markList = cons(this, markList); foriter (field, decl()->environ()->allProperDecls(), EnvironIter) { if ((field->category() == Decl::Field) && (field->hasType()) && !(field->modifiers() & Static)) { string fullname = myname + "." + field->cFieldName(); // Special case...points have this funny "val" thing that looks like // an arrayref but isn't. if (fullname.find("tiPoint") != string::npos) { continue; } llist *fieldGptrs = field->type()->findGptrs(fullname, false); gpnames = extend(gpnames, fieldGptrs); } } } return gpnames; } bool FieldAccessNode::isFieldOfImmutable() const { return !(decl()->modifiers() & Static) && accessedObjectType()->isImmutable(); } /* If the subtree "rhs" is a global pointer or is an immutable with global pointer fields, this routine generates code that informs the global GC about an escape, *if* the codegen'ed integer expression "targetNode" != MYBOX. */ void checkPointerEscape(TreeNode *rhs, string valstr, string targetNode, bool checkPrivate, string exprStr, CodeContext &context) { llist *escPtrs = rhs->type()->findGptrs(valstr); if (escPtrs) { if (targetNode != "") { context << "if (" << targetNode << " != MYBOX)" << endCline; } context << "{" << endCline; while (escPtrs) { context << "\tGC_PTR_ESC(&(" << escPtrs->front() << "), 1);" << endCline; if (checkPrivate) { context << "\tCHECK_PTR_TO_SHARED_IFBC(" << escPtrs->front() << ", \"" << exprStr << "\", \"" << rhs->position().asString() << "\");" << endCline; } escPtrs = escPtrs->free(); } context << "}" << endCline; } } const string AssignNode::emitExpression(CodeContext &context) { if (isCodeLiteralExprNode(opnd0()) || opnd0()->isSimpleLvalue()) if (isSRArrayAccessNode(opnd1())) { const TypeNode * arrayType = opnd1()->array()->type(); const TypeNode * elemType = arrayType->elementType(); const bool local = arrayType->isLocal(); extern string load(const string &dest, const string &address, const TypeNode *type, bool local); const string lhs = opnd0()->emitExpression(context); const string addr = opnd1()->getLvalue(context); arrayType->fencePreRead(context); if (local || !elemType->isLocal()) { context << load(lhs, addr, elemType, local) << ';' << endCline; arrayType->fencePostRead(context); return ""; } else { // when accessing a global array of local elements, the // resulting element value must be widened from local to global const string tmp = declareTemporary(context, elemType->cType()); context << load(tmp, addr, elemType, local) << ';' << endCline; arrayType->fencePostRead(context); return lhs + " = " + elemType->emitGlobalize(context, "TO_BOX(" + addr + ")", tmp); } } else return opnd0()->emitExpression(context) + " = " + opnd1()->emitExpression(context); if (opnd0()->isFieldOfImmutable()) { const string lval = opnd0()->getLvalue(context); const string value = opnd1()->emitExpression(context); context << "*(" << lval << ") = " << value << ";" << endCline; return ""; } const AssignKind kind = assignKind(type()); const string lval = opnd0()->getLvalue(context); const string value = opnd1()->simpleVar(context); if (!opnd0()->isLocalLvalue()) { string targetNode = "TO_BOX(" + lval + ")"; checkPointerEscape(opnd1(), value, targetNode, false, "", context); } opnd0()->receiveAssign(context, lval, value, kind, type()); return ""; }