#include "AST.h" #include "CodeContext.h" #include "CtReference.h" #include "FieldDecl.h" #include "code.h" #include "ctBox.h" #include "decls.h" #include "lgMacro.h" #include "code-assign.h" #include "code-util.h" const string TypeFieldAccessNode::emitExpression( CodeContext & ) { Decl *d = simpName()->decl(); //TreeNode *t = ftype()->decl()->asType(); // methods should go through emitMethodCall assert( !(d->category() & Decl::Method) ); assert( d->modifiers() & Common::Static ); assert(d->category() & Decl::Field); FieldDecl *fd = static_cast< FieldDecl * >(d); // side-effect free return "(STATIC_REF(" + fd->container()->cStaticFieldsStructName() + ", " + cFieldName(d) + "))"; } const string ObjectFieldAccessNode::emitExpression( CodeContext &context ) { Decl *d = simpName()->decl(); TypeNode &objectType = *accessedObjectType(); // methods should go through emitMethodCall assert( !(d->category() & Decl::Method) ); assert(d->category() & Decl::Field); FieldDecl *fd = static_cast< FieldDecl * >(d); if (d->modifiers() & Static) return "(STATIC_REF(" + fd->container()->cStaticFieldsStructName() + ", " + cFieldName(d) + "))"; string result; if ((objectType.isPointType() || objectType.isRectDomainType() || objectType.isTitaniumArrayType())) result = '(' + object()->emitExpression( context ) + ")." + *(d->name()); else if (objectType.isImmutable()) result = '(' + object()->emitExpression( context ) + "." + cFieldName(d) + ')'; else { const bool objectLocal = objectType.isLocal(); const string address = getLvalue( context ); const TypeNode &fieldType = *decl()->type(); const string fieldValue = declareTemporary( context, fieldType.cType() ); objectType.fencePreRead( context ); context << lgMacro( "DEREF", objectLocal ) << assignSuffix(assignType((const TypeNode *)&fieldType), objectLocal) << '(' << fieldValue << ", " << address << ");" << endCline; objectType.fencePostRead( context ); if (!objectLocal && fieldType.isLocal()) { // when accessing object.field, with a global object and a // local field, the resulting field value must be widened // from local to global const string box = "TO_BOX(" + address + ')'; result = fieldType.emitGlobalize( context, box, fieldValue ); } else result = fieldValue; } return result; } bool TypeFieldAccessNode::isLocalLvalue() { return true; } const string TypeFieldAccessNode::getLvalue( CodeContext & ) { Decl *d = simpName()->decl(); //TreeNode *t = ftype()->decl()->asType(); // methods should go through emitMethodCall assert( !(d->category() & Decl::Method) ); assert( d->modifiers() & Common::Static ); assert(d->category() & Decl::Field); FieldDecl *fd = static_cast< FieldDecl * >(d); // side-effect free string result; return string("(& STATIC_REF(") + fd->container()->cStaticFieldsStructName() + string(", ") + cFieldName(d) + string("))"); } bool ObjectFieldAccessNode::isLocalLvalue() { return accessedObjectType()->isLocal() || accessedObjectType()->isImmutable() || simpName()->decl()->modifiers() & Static; } const string ObjectFieldAccessNode::getLvalue( CodeContext &context ) { FieldDecl &d = static_cast< FieldDecl & >(*decl()); // methods should go through emitMethodCall assert( d.category() == Decl::Field ); if (d.modifiers() & Static) { object()->emitExpression(context); return string("(& STATIC_REF(") + d.container()->cStaticFieldsStructName() + string(", ") + cFieldName(&d) + string("))"); } TypeNode &objectType = *accessedObjectType(); assert(!objectType.isPointType()); assert(!objectType.isRectDomainType()); assert(!objectType.isTitaniumArrayType()); // need to know the interior layout of the containing instance context.depend( objectType.decl()->cType() ); string fieldName; if (objectType.isJavaArrayType()) { assert( *d.name() == "length" ); fieldName = "header.length"; } else fieldName = cFieldName(&d); if (objectType.isImmutable()) { // assignments to immutable objects only occur in constructors, and // to the fields of the object being constructed // DOB: this is no longer true, because we may inline immutable constructors, // so the immutable being assigned to could be any arbitrary immutable //return "&(" + MANGLE_THIS_VAR(+) + "." + fieldName + ')'; const string objectValue = object()->emitExpression( context ); return "&(" + objectValue + "." + fieldName + ')'; } else { const string objectValue = object()->emitExpression( context ); const bool objectLocal = objectType.isLocal(); if (!isThisNode(object())) { // can always elide nullcheck on "this" object context << lgMacro( "CHECK_NULL", objectLocal ) << "_IFBC(" << objectValue << ", \"" << object()->position().asString() << "\");" << endCline; } const CtReference &addrType = ctBox( d.cType(), objectLocal ); const string addrValue = declareTemporary( context, addrType ); context << lgMacro( "FIELD_ADDR", objectLocal ) << '(' << addrValue << ", " << objectValue << ", " << fieldName << ");" << endCline; return addrValue; } }