root/src/cmd/gc/unsafe.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. unsafenmagic
  2. isunsafebuiltin

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include <u.h>
#include <libc.h>
#include "go.h"

/*
 * look for
 *      unsafe.Sizeof
 *      unsafe.Offsetof
 *      unsafe.Alignof
 * rewrite with a constant
 */
Node*
unsafenmagic(Node *nn)
{
        Node *r, *n, *base, *r1;
        Sym *s;
        Type *t, *tr;
        vlong v;
        Val val;
        Node *fn;
        NodeList *args;

        fn = nn->left;
        args = nn->list;

        if(safemode || fn == N || fn->op != ONAME || (s = fn->sym) == S)
                goto no;
        if(s->pkg != unsafepkg)
                goto no;

        if(args == nil) {
                yyerror("missing argument for %S", s);
                goto no;
        }
        r = args->n;

        if(strcmp(s->name, "Sizeof") == 0) {
                typecheck(&r, Erv);
                defaultlit(&r, T);
                tr = r->type;
                if(tr == T)
                        goto bad;
                dowidth(tr);
                v = tr->width;
                goto yes;
        }
        if(strcmp(s->name, "Offsetof") == 0) {
                // must be a selector.
                if(r->op != OXDOT)
                        goto bad;
                // Remember base of selector to find it back after dot insertion.
                // Since r->left may be mutated by typechecking, check it explicitly
                // first to track it correctly.
                typecheck(&r->left, Erv);
                base = r->left;
                typecheck(&r, Erv);
                switch(r->op) {
                case ODOT:
                case ODOTPTR:
                        break;
                case OCALLPART:
                        yyerror("invalid expression %N: argument is a method value", nn);
                        v = 0;
                        goto ret;
                default:
                        goto bad;
                }
                v = 0;
                // add offsets for inserted dots.
                for(r1=r; r1->left!=base; r1=r1->left) {
                        switch(r1->op) {
                        case ODOT:
                                v += r1->xoffset;
                                break;
                        case ODOTPTR:
                                yyerror("invalid expression %N: selector implies indirection of embedded %N", nn, r1->left);
                                goto ret;
                        default:
                                dump("unsafenmagic", r);
                                fatal("impossible %#O node after dot insertion", r1->op);
                                goto bad;
                        }
                }
                v += r1->xoffset;
                goto yes;
        }
        if(strcmp(s->name, "Alignof") == 0) {
                typecheck(&r, Erv);
                defaultlit(&r, T);
                tr = r->type;
                if(tr == T)
                        goto bad;

                // make struct { byte; T; }
                t = typ(TSTRUCT);
                t->type = typ(TFIELD);
                t->type->type = types[TUINT8];
                t->type->down = typ(TFIELD);
                t->type->down->type = tr;
                // compute struct widths
                dowidth(t);

                // the offset of T is its required alignment
                v = t->type->down->width;
                goto yes;
        }

no:
        return N;

bad:
        yyerror("invalid expression %N", nn);
        v = 0;
        goto ret;

yes:
        if(args->next != nil)
                yyerror("extra arguments for %S", s);
ret:
        // any side effects disappear; ignore init
        val.ctype = CTINT;
        val.u.xval = mal(sizeof(*n->val.u.xval));
        mpmovecfix(val.u.xval, v);
        n = nod(OLITERAL, N, N);
        n->orig = nn;
        n->val = val;
        n->type = types[TUINTPTR];
        nn->type = types[TUINTPTR];
        return n;
}

int
isunsafebuiltin(Node *n)
{
        if(n == N || n->op != ONAME || n->sym == S || n->sym->pkg != unsafepkg)
                return 0;
        if(strcmp(n->sym->name, "Sizeof") == 0)
                return 1;
        if(strcmp(n->sym->name, "Offsetof") == 0)
                return 1;
        if(strcmp(n->sym->name, "Alignof") == 0)
                return 1;
        return 0;
}

/* [<][>][^][v][top][bottom][index][help] */