mirror of https://github.com/golang/go.git
149 lines
2.9 KiB
C
149 lines
2.9 KiB
C
// 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;
|
|
long 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;
|
|
}
|