-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathMakefile
More file actions
116 lines (89 loc) · 4.49 KB
/
Copy pathMakefile
File metadata and controls
116 lines (89 loc) · 4.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
V8_ROOT ?= /v8/v8
V8_OUT ?= out/rel
BUILD ?= build
V8_LIB := $(V8_ROOT)/$(V8_OUT)/obj/libv8_monolith.a
# Use the clang that built the monolith. Mixing compilers across the boundary
# is asking for trouble even when libc++ matches.
#
# `=`, NOT `?=`. make predefines CXX as g++ via its built-in rules, so `?=`
# never fires and the embedder silently builds with the system compiler. A
# plain `=` still loses to a command-line `make CXX=...`, which is what we want.
CXX = $(V8_ROOT)/third_party/llvm-build/Release+Asserts/bin/clang++
# The ABI-affecting defines (V8_COMPRESS_POINTERS, V8_ENABLE_SANDBOX,
# V8_31BIT_SMIS_ON_64BIT_ARCH, ...) are read out of the actual build rather than
# hardcoded. Getting these wrong produces silent heap corruption, so never
# type them by hand.
# The real gn binary, not the depot_tools shim. The shim is a Python wrapper
# that refuses to run without a bootstrapped depot_tools (python3_bin_reldir.txt)
# and prints its complaint to stdout, which would make V8_DEFINES empty --
# the exact silent-corruption case verify-abi exists to catch.
GN ?= $(V8_ROOT)/buildtools/linux64/gn
V8_DEFINES := $(shell cd $(V8_ROOT) && $(GN) desc $(V8_OUT) //:v8_monolith defines \
| sed 's/^/-D/' | tr '\n' ' ')
INCLUDES := -I. -I$(V8_ROOT) -I$(V8_ROOT)/include
CXXFLAGS := -std=c++20 -O2 -fno-rtti -fPIE \
-ffunction-sections -fdata-sections \
-Wall -Wextra -Wno-unused-parameter \
$(INCLUDES) $(V8_DEFINES)
# -fuse-ld=lld is required, not a preference: is_official_build=true builds the
# monolith with ThinLTO, so libv8_monolith.a holds LLVM bitcode rather than ELF
# objects. GNU ld rejects it outright with
# "error adding symbols: file format not recognized".
# lld ships in the same third_party/llvm-build directory as the clang above.
LDFLAGS := -static-pie -fuse-ld=lld -Wl,--gc-sections -Wl,-O2
LIBS := $(V8_LIB) -lstdc++ -lm -ldl -lpthread
SNAPSHOT := $(BUILD)/snapshot.bin
.PHONY: all snapshot clean size check verify-abi
all: $(BUILD)/jsvm
# --- stage 1: the snapshot builder, which must NOT itself use a snapshot -----
$(BUILD)/bindings.o: src/bindings.cc src/bindings.h | $(BUILD)
$(CXX) $(CXXFLAGS) -c $< -o $@
$(BUILD)/mksnapshot_tool.o: src/mksnapshot_tool.cc src/bindings.h | $(BUILD)
$(CXX) $(CXXFLAGS) -c $< -o $@
$(BUILD)/mksnapshot_tool: $(BUILD)/mksnapshot_tool.o $(BUILD)/bindings.o
$(CXX) $(LDFLAGS) $^ $(LIBS) -o $@
$(SNAPSHOT): $(BUILD)/mksnapshot_tool src/preload.js
$(BUILD)/mksnapshot_tool src/preload.js $@
snapshot: $(SNAPSHOT)
# --- stage 2: the runner, with the blob linked in via .incbin ----------------
# .S (capital) so clang runs the preprocessor and JSVM_SNAPSHOT_FILE expands.
$(BUILD)/snapshot_blob.o: src/snapshot_blob.S $(SNAPSHOT)
$(CXX) -c -x assembler-with-cpp \
-DJSVM_SNAPSHOT_FILE='"$(SNAPSHOT)"' $< -o $@
$(BUILD)/jsvm.o: src/jsvm.cc src/bindings.h | $(BUILD)
$(CXX) $(CXXFLAGS) -DJSVM_EMBEDDED_SNAPSHOT -c $< -o $@
$(BUILD)/jsvm: $(BUILD)/jsvm.o $(BUILD)/bindings.o $(BUILD)/snapshot_blob.o
$(CXX) $(LDFLAGS) $^ $(LIBS) -o $@
strip -s $@
$(BUILD):
mkdir -p $(BUILD)
# --- diagnostics -------------------------------------------------------------
# Run this after any V8 bump. An empty result means gn desc failed and the
# defines silently vanished, which is the corruption scenario.
verify-abi:
@test -n "$(V8_DEFINES)" || { echo "FATAL: no defines from gn desc"; exit 1; }
@echo "$(V8_DEFINES)" | tr ' ' '\n' | grep -E 'POINTER|SANDBOX|SMIS' || true
size: $(BUILD)/jsvm
@ls -la $(BUILD)/jsvm
@echo "snapshot: $$(stat -c %s $(SNAPSHOT)) bytes"
@file $(BUILD)/jsvm
@ldd $(BUILD)/jsvm 2>&1 | head -3 || true
check: $(BUILD)/jsvm
@echo '1+1' | $(BUILD)/jsvm
@echo 'jsvm.emit({from:"snapshot"})' | $(BUILD)/jsvm --quiet
@echo 'while(true){}' | $(BUILD)/jsvm --timeout=250 ; \
test $$? -eq 124 && echo "timeout: ok"
@# Asserts the ceiling is ENFORCED and REPORTED, not the exit code: V8 aborts
@# on heap exhaustion without consulting the OOM handler, so 125 is
@# unreachable in this build. See the AddNearHeapLimitCallback comment in
@# src/jsvm.cc. What matters is that 32MB stops it and says why.
@out=$$(echo 'const a=[];for(;;)a.push(new Array(1e5).fill(0))' \
| $(BUILD)/jsvm --heap=32 2>&1 || true); \
case "$$out" in \
*"Last few GCs"*) echo "heap cap: ok (enforced, V8 OOM report)" ;; \
*) echo "heap cap: FAILED -- no OOM report:"; echo "$$out"; exit 1 ;; \
esac
@echo 'throw new Error("boom")' | $(BUILD)/jsvm ; \
test $$? -eq 1 && echo "error path: ok"
clean:
rm -rf $(BUILD)