Skip to content

Commit 28aeda4

Browse files
committed
Separate the PNaCl llc into a tool named pnacl-llc (how original!)
BUG=None [email protected] Review URL: https://codereview.chromium.org/14604011
1 parent c5d1983 commit 28aeda4

10 files changed

+1314
-2
lines changed

tools/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ add_subdirectory(llvm-dis)
1414
add_subdirectory(llvm-mc)
1515

1616
add_subdirectory(llc)
17+
add_subdirectory(pnacl-llc)
1718
add_subdirectory(llvm-ranlib)
1819
add_subdirectory(llvm-ar)
1920
add_subdirectory(llvm-nm)

tools/LLVMBuild.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
;===------------------------------------------------------------------------===;
1717

1818
[common]
19-
subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-ranlib llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup pnacl-abicheck pnacl-bcanalyzer pnacl-freeze pnacl-thaw
19+
subdirectories = bugpoint llc pnacl-llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-ranlib llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup pnacl-abicheck pnacl-bcanalyzer pnacl-freeze pnacl-thaw
2020

2121
[component_0]
2222
type = Group

tools/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ OPTIONAL_DIRS := lldb
2828
# in parallel builds. Please retain this ordering.
2929
DIRS := llvm-config
3030
PARALLEL_DIRS := opt llvm-as llvm-dis \
31-
llc llvm-ranlib llvm-ar llvm-nm \
31+
llc pnacl-llc llvm-ranlib llvm-ar llvm-nm \
3232
llvm-prof llvm-link \
3333
lli llvm-extract llvm-mc \
3434
bugpoint llvm-bcanalyzer \

tools/pnacl-llc/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser naclanalysis)
2+
3+
add_llvm_tool(pnacl-llc
4+
# This file provides wrappers to lseek(2), read(2), etc.
5+
nacl_file.cpp
6+
SRPCStreamer.cpp
7+
pnacl-llc.cpp
8+
)

tools/pnacl-llc/LLVMBuild.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
;===- ./tools/pnacl-llc/LLVMBuild.txt --------------------------*- Conf -*--===;
2+
;
3+
; The LLVM Compiler Infrastructure
4+
;
5+
; This file is distributed under the University of Illinois Open Source
6+
; License. See LICENSE.TXT for details.
7+
;
8+
;===------------------------------------------------------------------------===;
9+
;
10+
; This is an LLVMBuild description file for the components in this subdirectory.
11+
;
12+
; For more information on the LLVMBuild system, please see:
13+
;
14+
; http://llvm.org/docs/LLVMBuild.html
15+
;
16+
;===------------------------------------------------------------------------===;
17+
18+
[component_0]
19+
type = Tool
20+
name = pnacl-llc
21+
parent = Tools
22+
required_libraries = AsmParser BitReader all-targets NaClAnalysis

tools/pnacl-llc/Makefile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#===- tools/pnacl-llc/Makefile -----------------------------*- Makefile -*-===##
2+
#
3+
# The LLVM Compiler Infrastructure
4+
#
5+
# This file is distributed under the University of Illinois Open Source
6+
# License. See LICENSE.TXT for details.
7+
#
8+
##===----------------------------------------------------------------------===##
9+
10+
LEVEL := ../..
11+
TOOLNAME := pnacl-llc
12+
LINK_COMPONENTS := all-targets bitreader asmparser naclanalysis
13+
14+
include $(LEVEL)/Makefile.common
15+

tools/pnacl-llc/SRPCStreamer.cpp

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//===-- SRPCStreamer.cpp - Stream bitcode over SRPC ----------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
//
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#if defined(__native_client__) && defined(NACL_SRPC)
15+
#define DEBUG_TYPE "bitcode-stream"
16+
#include "SRPCStreamer.h"
17+
#include "llvm/Support/Debug.h"
18+
#include "llvm/Support/raw_ostream.h"
19+
#include <errno.h>
20+
21+
using llvm::dbgs;
22+
23+
const size_t QueueStreamer::queuesize_limit_;
24+
25+
size_t QueueStreamer::GetBytes(unsigned char *buf, size_t len) {
26+
size_t total_copied = 0;
27+
pthread_mutex_lock(&Mutex);
28+
while (!Done && queueSize() < len - total_copied) {
29+
size_t size = queueSize();
30+
DEBUG(dbgs() << "QueueStreamer::GetBytes len " << len << " size " <<
31+
size << " << waiting\n");
32+
queueGet(buf + total_copied, size);
33+
total_copied += size;
34+
pthread_cond_signal(&Cond);
35+
pthread_cond_wait(&Cond, &Mutex);
36+
}
37+
// If this is the last partial chunk, adjust len such that the amount we
38+
// fetch will be just the remaining bytes.
39+
if (Done && queueSize() < len - total_copied) {
40+
len = queueSize() + total_copied;
41+
}
42+
queueGet(buf + total_copied, len - total_copied);
43+
pthread_cond_signal(&Cond);
44+
pthread_mutex_unlock(&Mutex);
45+
return len;
46+
}
47+
48+
size_t QueueStreamer::PutBytes(unsigned char *buf, size_t len) {
49+
size_t total_copied = 0;
50+
pthread_mutex_lock(&Mutex);
51+
while (capacityRemaining() < len - total_copied) {
52+
if (Bytes.size() * 2 > queuesize_limit_) {
53+
size_t space = capacityRemaining();
54+
queuePut(buf + total_copied, space);
55+
total_copied += space;
56+
pthread_cond_signal(&Cond);
57+
pthread_cond_wait(&Cond, &Mutex);
58+
} else {
59+
queueResize();
60+
}
61+
}
62+
queuePut(buf + total_copied, len - total_copied);
63+
pthread_cond_signal(&Cond);
64+
pthread_mutex_unlock(&Mutex);
65+
return len;
66+
}
67+
68+
void QueueStreamer::SetDone() {
69+
// Still need the lock to avoid signaling between the check and
70+
// the wait in GetBytes.
71+
pthread_mutex_lock(&Mutex);
72+
Done = true;
73+
pthread_cond_signal(&Cond);
74+
pthread_mutex_unlock(&Mutex);
75+
}
76+
77+
// Double the size of the queue. Called with Mutex to protect Cons/Prod/Bytes.
78+
void QueueStreamer::queueResize() {
79+
int leftover = Bytes.size() - Cons;
80+
DEBUG(dbgs() << "resizing to " << Bytes.size() * 2 << " " << leftover << " "
81+
<< Prod << " " << Cons << "\n");
82+
Bytes.resize(Bytes.size() * 2);
83+
if (Cons > Prod) {
84+
// There are unread bytes left between Cons and the previous end of the
85+
// buffer. Move them to the new end of the buffer.
86+
memmove(&Bytes[Bytes.size() - leftover], &Bytes[Cons], leftover);
87+
Cons = Bytes.size() - leftover;
88+
}
89+
}
90+
91+
// Called with Mutex held to protect Cons, Prod, and Bytes
92+
void QueueStreamer::queuePut(unsigned char *buf, size_t len) {
93+
size_t EndSpace = std::min(len, Bytes.size() - Prod);
94+
DEBUG(dbgs() << "put, len " << len << " Endspace " << EndSpace << " p " <<
95+
Prod << " c " << Cons << "\n");
96+
// Copy up to the end of the buffer
97+
memcpy(&Bytes[Prod], buf, EndSpace);
98+
// Wrap around if necessary
99+
memcpy(&Bytes[0], buf + EndSpace, len - EndSpace);
100+
Prod = (Prod + len) % Bytes.size();
101+
}
102+
103+
// Called with Mutex held to protect Cons, Prod, and Bytes
104+
void QueueStreamer::queueGet(unsigned char *buf, size_t len) {
105+
assert(len <= queueSize());
106+
size_t EndSpace = std::min(len, Bytes.size() - Cons);
107+
DEBUG(dbgs() << "get, len " << len << " Endspace " << EndSpace << " p " <<
108+
Prod << " c " << Cons << "\n");
109+
// Copy up to the end of the buffer
110+
memcpy(buf, &Bytes[Cons], EndSpace);
111+
// Wrap around if necessary
112+
memcpy(buf + EndSpace, &Bytes[0], len - EndSpace);
113+
Cons = (Cons + len) % Bytes.size();
114+
}
115+
116+
llvm::DataStreamer *SRPCStreamer::init(void *(*Callback)(void *), void *arg,
117+
std::string *ErrMsg) {
118+
int err = pthread_create(&CompileThread, NULL, Callback, arg);
119+
if (err) {
120+
if (ErrMsg) *ErrMsg = std::string(strerror(errno));
121+
return NULL;
122+
}
123+
return &Q;
124+
}
125+
126+
size_t SRPCStreamer::gotChunk(unsigned char *bytes, size_t len) {
127+
if (Error) return 0;
128+
return Q.PutBytes(bytes, len);
129+
}
130+
131+
int SRPCStreamer::streamEnd(std::string *ErrMsg) {
132+
Q.SetDone();
133+
int err = pthread_join(CompileThread, NULL);
134+
if (err) {
135+
if (ErrMsg) *ErrMsg = std::string(strerror(errno));
136+
return err;
137+
}
138+
if (Error && ErrMsg) *ErrMsg = std::string("compile failed.");
139+
return Error;
140+
}
141+
142+
#endif

tools/pnacl-llc/SRPCStreamer.h

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//===-- SRPCStreamer.cpp - Stream bitcode over SRPC ----------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
//
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef SRPCSTREAMER_H
15+
#define SRPCSTREAMER_H
16+
17+
#include <pthread.h>
18+
#include <cassert>
19+
#include <cstdio>
20+
#include <cstring>
21+
#include <vector>
22+
#include "llvm/Support/DataStream.h"
23+
24+
// Implements LLVM's interface for fetching data from a stream source.
25+
// Bitcode bytes from the RPC thread are placed here with PutBytes and buffered
26+
// until the bitcode reader calls GetBytes to remove them.
27+
// The blocking behavior of GetBytes and PutBytes means that if the
28+
// compilation happens faster than the bytes come in from the browser, the
29+
// whole pipeline can block waiting for the RPC thread to put more bytes.
30+
31+
class QueueStreamer : public llvm::DataStreamer {
32+
public:
33+
QueueStreamer() : Done(false), Prod(0), Cons(0) {
34+
pthread_mutex_init(&Mutex, NULL);
35+
pthread_cond_init(&Cond, NULL);
36+
Bytes.resize(64 * 1024);
37+
}
38+
39+
// Called by the compilation thread. Copy len bytes from the queue into
40+
// buf. If there are less than len bytes available, copy as many as
41+
// there are, signal the RPC thread, and block to wait for the rest.
42+
// If all bytes have been received from the browser and there are
43+
// fewer than len bytes available, copy all remaining bytes.
44+
// Return the number of bytes copied.
45+
virtual size_t GetBytes(unsigned char *buf, size_t len);
46+
47+
// Called by the RPC thread. Copy len bytes from buf into the queue.
48+
// If there is not enough space in the queue, copy as many bytes as
49+
// will fit, signal the compilation thread, and block until there is
50+
// enough space for the rest.
51+
// Return the number of bytes copied.
52+
size_t PutBytes(unsigned char *buf, size_t len);
53+
54+
// Called by the RPC thread. Signal that all bytes have been received,
55+
// so the last call to GetBytes will return the remaining bytes rather
56+
// than waiting for the entire requested amound.
57+
void SetDone();
58+
59+
private:
60+
bool Done;
61+
pthread_mutex_t Mutex;
62+
pthread_cond_t Cond;
63+
// Maximum size of the queue. The limitation on the queue size means that
64+
// if the compilation happens slower than bytes arrive from the network,
65+
// the queue will fill up, the RPC thread will be blocked most of the time,
66+
// the RPC thread on the browser side will be waiting for the SRPC to return,
67+
// and the buffer on the browser side will grow unboundedly until the
68+
// whole bitcode file arrives (which is better than having the queue on
69+
// the untrusted side consume all that memory).
70+
// The partial-copying behavior of GetBytes and PutBytes prevents deadlock
71+
// even if the requested number of bytes is greater than the size limit
72+
// (although it will of course be less efficient).
73+
// The initial size of the queue is expected to be smaller than this, but
74+
// if not, it will simply never be resized.
75+
const static size_t queuesize_limit_ = 256 * 1024;
76+
77+
// Variables and functions to manage the circular queue
78+
std::vector<unsigned char> Bytes;
79+
size_t Prod; // Queue producer index
80+
size_t Cons; // Queue consumer index
81+
size_t queueSize() {
82+
return Prod >= Cons ? Prod - Cons : Bytes.size() - (Cons - Prod);
83+
}
84+
size_t capacityRemaining() {
85+
return (Prod >= Cons ? Bytes.size() - (Prod - Cons) : (Cons - Prod)) - 1;
86+
}
87+
void queueResize();
88+
void queuePut(unsigned char *buf, size_t len);
89+
void queueGet(unsigned char *buf, size_t len);
90+
};
91+
92+
// Class to manage the compliation thread and serve as the interface from
93+
// the SRPC thread
94+
class SRPCStreamer {
95+
public:
96+
SRPCStreamer() : Error(false) {}
97+
// Initialize streamer, create a new thread running Callback, and
98+
// return a pointer to the DataStreamer the threads will use to
99+
// synchronize. On error, return NULL and fill in the ErrorMsg string
100+
llvm::DataStreamer *init(void *(*Callback)(void *),
101+
void *arg, std::string *ErrMsg);
102+
// Called by the RPC thread. Copy len bytes from buf. Return bytes copied.
103+
size_t gotChunk(unsigned char *bytes, size_t len);
104+
// Called by the RPC thread. Wait for the compilation thread to finish.
105+
int streamEnd(std::string *ErrMsg);
106+
// Called by the compilation thread. Signal that there was a compilation
107+
// error so the RPC thread can abort the stream.
108+
void setError() { Error = true; }
109+
private:
110+
bool Error;
111+
QueueStreamer Q;
112+
pthread_t CompileThread;
113+
};
114+
115+
116+
117+
#endif // SRPCSTREAMER_H

0 commit comments

Comments
 (0)