summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/nacl/386/closure.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/nacl/386/closure.c')
-rw-r--r--src/pkg/runtime/nacl/386/closure.c247
1 files changed, 0 insertions, 247 deletions
diff --git a/src/pkg/runtime/nacl/386/closure.c b/src/pkg/runtime/nacl/386/closure.c
deleted file mode 100644
index 6a27d6ec6..000000000
--- a/src/pkg/runtime/nacl/386/closure.c
+++ /dev/null
@@ -1,247 +0,0 @@
-// 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.
-
-/*
- * Closure implementation for Native Client.
- * Native Client imposes some interesting restrictions.
- *
- * First, we can only add new code to the code segment
- * through a special system call, and we have to pick the
- * maximum amount of code we're going to add that way
- * at link time (8l reserves 512 kB for us).
- *
- * Second, once we've added the code we can't ever
- * change it or delete it. If we want to garbage collect
- * the memory and then reuse it for another closure,
- * we have to do so without editing the code.
- *
- * To address both of these, we fill the code segment pieces
- * with very stylized closures. Each has the form given below
- * in the comments on the closasm array, with ** replaced by
- * a pointer to a single word of memory. The garbage collector
- * treats a pointer to such a closure as equivalent to the value
- * held in **. This tiled run of closures is called the closure array.
- *
- * The ptr points at a ClosureData structure, defined below,
- * which gives the function, arguments, and size for the
- * closuretramp function. The ClosureData structure has
- * in it a pointer to a ClosureFreeList structure holding the index
- * of the closure in the closure array (but not a pointer to it).
- * That structure has a finalizer: when the garbage collector
- * notices that the ClosureFreeList structure is not referenced
- * anymore, that means the closure is not referenced, so it
- * can be reused. To do that, the ClosureFreeList entry is put
- * onto an actual free list.
- */
-#include "runtime.h"
-#include "malloc.h"
-
-// NaCl system call to copy data into text segment.
-extern int32 dyncode_copy(void*, void*, int32);
-
-enum{
- // Allocate chunks of 4096 bytes worth of closures:
- // at 64 bytes each, that's 64 closures.
- ClosureChunk = 4096,
- ClosureSize = 64,
-};
-
-typedef struct ClosureFreeList ClosureFreeList;
-struct ClosureFreeList
-{
- ClosureFreeList *next;
- int32 index; // into closure array
-};
-
-// Known to closasm
-typedef struct ClosureData ClosureData;
-struct ClosureData
-{
- ClosureFreeList *free;
- byte *fn;
- int32 siz;
- // then args
-};
-
-// List of the closure data pointer blocks we've allocated
-// and hard-coded in the closure text segments.
-// The list keeps the pointer blocks from getting collected.
-typedef struct ClosureDataList ClosureDataList;
-struct ClosureDataList
-{
- ClosureData **block;
- ClosureDataList *next;
-};
-
-static struct {
- Lock;
- byte *code;
- byte *ecode;
- ClosureFreeList *free;
- ClosureDataList *datalist;
- byte buf[ClosureChunk];
-} clos;
-
-static byte closasm[64] = {
- 0x8b, 0x1d, 0, 0, 0, 0, // MOVL **, BX
- 0x8b, 0x4b, 8, // MOVL 8(BX), CX
- 0x8d, 0x73, 12, // LEAL 12(BX), SI
- 0x29, 0xcc, // SUBL CX, SP
- 0x89, 0xe7, // MOVL SP, DI
- 0xc1, 0xe9, 2, // SHRL $2, CX
- 0xf3, 0xa5, // REP MOVSL
- 0x8b, 0x5b, 4, // MOVL 4(BX), BX
- 0x90, 0x90, 0x90, // NOP...
- 0x83, 0xe3, ~31, // ANDL $~31, BX
- 0xff, 0xd3, // CALL *BX
- // --- 32-byte boundary
- 0x8b, 0x1d, 0, 0, 0, 0, // MOVL **, BX
- 0x03, 0x63, 8, // ADDL 8(BX), SP
- 0x5b, // POPL BX
- 0x83, 0xe3, ~31, // ANDL $~31, BX
- 0xff, 0xe3, // JMP *BX
- 0xf4, // HLT...
- 0xf4, 0xf4, 0xf4, 0xf4,
- 0xf4, 0xf4, 0xf4, 0xf4,
- 0xf4, 0xf4, 0xf4, 0xf4,
- 0xf4, 0xf4, 0xf4, 0xf4,
- // --- 32-byte boundary
-};
-
-// Returns immediate pointer from closure code block.
-// Triple pointer:
-// p is the instruction stream
-// p+2 is the location of the immediate value
-// *(p+2) is the immediate value, a word in the pointer block
-// permanently associated with this closure.
-// **(p+2) is the ClosureData* pointer temporarily associated
-// with this closure.
-//
-#define codeptr(p) *(ClosureData***)((byte*)(p)+2)
-
-void
-finclosure(void *v)
-{
- byte *p;
- ClosureFreeList *f;
-
- f = v;
- p = clos.code + f->index*ClosureSize;
- *codeptr(p) = nil;
-
- lock(&clos);
- f->next = clos.free;
- clos.free = f;
- unlock(&clos);
-}
-
-#pragma textflag 7
-// func closure(siz int32,
-// fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
-// arg0, arg1, arg2 *ptr) (func(xxx) yyy)
-void
-·closure(int32 siz, byte *fn, byte *arg0)
-{
- byte *p, **ret;
- int32 e, i, n, off;
- extern byte data[], etext[];
- ClosureData *d, **block;
- ClosureDataList *l;
- ClosureFreeList *f;
-
- if(siz < 0 || siz%4 != 0)
- throw("bad closure size");
-
- ret = (byte**)((byte*)&arg0 + siz);
-
- if(siz > 100) {
- // TODO(rsc): implement stack growth preamble?
- throw("closure too big");
- }
-
- lock(&clos);
- if(clos.free == nil) {
- // Allocate more closures.
- if(clos.code == nil) {
- // First time: find closure space, between end of text
- // segment and beginning of data.
- clos.code = (byte*)(((uintptr)etext + 65535) & ~65535);
- clos.ecode = clos.code;
- mheap.closure_min = clos.code;
- mheap.closure_max = data;
- }
- if(clos.ecode+ClosureChunk > data) {
- // Last ditch effort: garbage collect and hope.
- unlock(&clos);
- gc(1);
- lock(&clos);
- if(clos.free != nil)
- goto alloc;
- throw("ran out of room for closures in text segment");
- }
-
- n = ClosureChunk/ClosureSize;
-
- // Allocate the pointer block as opaque to the
- // garbage collector. Finalizers will clean up.
- block = mallocgc(n*sizeof block[0], RefNoPointers, 1, 1);
-
- // Pointers into the pointer block are getting added
- // to the text segment; keep a pointer here in the data
- // segment so that the garbage collector doesn't free
- // the block itself.
- l = mal(sizeof *l);
- l->block = block;
- l->next = clos.datalist;
- clos.datalist = l;
-
- p = clos.buf;
- off = (clos.ecode - clos.code)/ClosureSize;
- for(i=0; i<n; i++) {
- f = mal(sizeof *f);
- f->index = off++;
- f->next = clos.free;
- clos.free = f;
-
- // There are two hard-coded immediate values in
- // the assembly that need to be pp+i, one 2 bytes in
- // and one 2 bytes after the 32-byte boundary.
- mcpy(p, closasm, ClosureSize);
- *(ClosureData***)(p+2) = block+i;
- *(ClosureData***)(p+32+2) = block+i;
- p += ClosureSize;
- }
-
- if(p != clos.buf+sizeof clos.buf)
- throw("bad buf math in closure");
-
- e = dyncode_copy(clos.ecode, clos.buf, ClosureChunk);
- if(e != 0) {
- fd = 2;
- printf("dyncode_copy: error %d\n", e);
- throw("dyncode_copy");
- }
- clos.ecode += ClosureChunk;
- }
-
-alloc:
- // Grab a free closure and save the data pointer in its indirect pointer.
- f = clos.free;
- clos.free = f->next;
- f->next = nil;
- p = clos.code + f->index*ClosureSize;
-
- d = mal(sizeof(*d)+siz);
- d->free = f;
- d->fn = fn;
- d->siz = siz;
- mcpy((byte*)(d+1), (byte*)&arg0, siz);
- *codeptr(p) = d;
- addfinalizer(f, finclosure, 0);
- unlock(&clos);
-
- *ret = p;
-}
-
-