Source code

Revision control

Other Tools

1
# This Source Code Form is subject to the terms of the Mozilla Public
2
# License, v. 2.0. If a copy of the MPL was not distributed with this
3
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
#
5
# ToCAsciiArray and ToCArray are from V8's js2c.py.
6
#
7
# Copyright 2012 the V8 project authors. All rights reserved.
8
# Redistribution and use in source and binary forms, with or without
9
# modification, are permitted provided that the following conditions are
10
# met:
11
#
12
# * Redistributions of source code must retain the above copyright
13
# notice, this list of conditions and the following disclaimer.
14
# * Redistributions in binary form must reproduce the above
15
# copyright notice, this list of conditions and the following
16
# disclaimer in the documentation and/or other materials provided
17
# with the distribution.
18
# * Neither the name of Google Inc. nor the names of its
19
# contributors may be used to endorse or promote products derived
20
# from this software without specific prior written permission.
21
#
22
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34
# This utility converts JS files containing self-hosted builtins into a C
35
# header file that can be embedded into SpiderMonkey.
36
#
37
# It uses the C preprocessor to process its inputs.
38
39
from __future__ import with_statement
40
41
import errno
42
import re
43
import sys
44
import os
45
import subprocess
46
import shlex
47
48
import buildconfig
49
import mozpack.path as mozpath
50
from mozfile import which
51
52
53
def ToCAsciiArray(lines):
54
result = []
55
for chr in lines:
56
value = ord(chr)
57
assert value < 128
58
result.append(str(value))
59
return ", ".join(result)
60
61
62
def ToCArray(lines):
63
result = []
64
for chr in lines:
65
result.append(str(ord(chr)))
66
return ", ".join(result)
67
68
69
HEADER_TEMPLATE = """\
70
/* This Source Code Form is subject to the terms of the Mozilla Public
71
* License, v. 2.0. If a copy of the MPL was not distributed with this
72
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
73
74
namespace js {
75
namespace %(namespace)s {
76
static const %(sources_type)s data[] = { %(sources_data)s };
77
78
static const %(sources_type)s * const %(sources_name)s = reinterpret_cast<const %(sources_type)s *>(data);
79
80
uint32_t GetCompressedSize() {
81
return %(compressed_total_length)i;
82
}
83
84
uint32_t GetRawScriptsSize() {
85
return %(raw_total_length)i;
86
}
87
} // selfhosted
88
} // js
89
""" # NOQA: E501
90
91
92
def embed(cxx, preprocessorOption, cppflags, msgs, sources, c_out, js_out, namespace, env):
93
objdir = os.getcwd()
94
# Use relative pathnames to avoid path translation issues in WSL.
95
combinedSources = '\n'.join([msgs] + ['#include "%(s)s"' %
96
{'s': mozpath.relpath(source, objdir)}
97
for source in sources])
98
args = cppflags + ['-D%(k)s=%(v)s' % {'k': k, 'v': env[k]} for k in env]
99
preprocessed = preprocess(cxx, preprocessorOption, combinedSources, args)
100
processed = '\n'.join([line for line in preprocessed.splitlines() if
101
(line.strip() and not line.startswith('#'))])
102
103
js_out.write(processed)
104
import zlib
105
compressed = zlib.compress(processed)
106
data = ToCArray(compressed)
107
c_out.write(HEADER_TEMPLATE % {
108
'sources_type': 'unsigned char',
109
'sources_data': data,
110
'sources_name': 'compressedSources',
111
'compressed_total_length': len(compressed),
112
'raw_total_length': len(processed),
113
'namespace': namespace
114
})
115
116
117
def preprocess(cxx, preprocessorOption, source, args=[]):
118
if (not os.path.exists(cxx[0])):
119
binary = cxx[0]
120
cxx[0] = which(binary)
121
if not cxx[0]:
122
raise OSError(errno.ENOENT, "%s not found on PATH" % binary)
123
124
# Clang seems to complain and not output anything if the extension of the
125
# input is not something it recognizes, so just fake a .cpp here.
126
tmpIn = 'self-hosting-cpp-input.cpp'
127
tmpOut = 'self-hosting-preprocessed.pp'
128
outputArg = shlex.split(preprocessorOption + tmpOut)
129
130
with open(tmpIn, 'wb') as input:
131
input.write(source)
132
print(' '.join(cxx + outputArg + args + [tmpIn]))
133
result = subprocess.Popen(cxx + outputArg + args + [tmpIn]).wait()
134
if (result != 0):
135
sys.exit(result)
136
with open(tmpOut, 'r') as output:
137
processed = output.read()
138
os.remove(tmpIn)
139
os.remove(tmpOut)
140
return processed
141
142
143
def messages(jsmsg):
144
defines = []
145
for line in open(jsmsg):
146
match = re.match("MSG_DEF\((JSMSG_(\w+))", line)
147
if match:
148
defines.append("#define %s %i" % (match.group(1), len(defines)))
149
else:
150
# Make sure that MSG_DEF isn't preceded by whitespace
151
assert not line.strip().startswith("MSG_DEF")
152
return '\n'.join(defines)
153
154
155
def get_config_defines(buildconfig):
156
# Collect defines equivalent to ACDEFINES and add MOZ_DEBUG_DEFINES.
157
env = buildconfig.defines['ALLDEFINES']
158
for define in buildconfig.substs['MOZ_DEBUG_DEFINES']:
159
env[define] = 1
160
return env
161
162
163
def process_inputs(namespace, c_out, msg_file, inputs):
164
deps = [path for path in inputs if path.endswith(".h") or path.endswith(".h.js")]
165
sources = [path for path in inputs if path.endswith(".js") and not path.endswith(".h.js")]
166
assert len(deps) + len(sources) == len(inputs)
167
cxx = shlex.split(buildconfig.substs['CXX'])
168
pp_option = buildconfig.substs['PREPROCESS_OPTION']
169
cppflags = buildconfig.substs['OS_CPPFLAGS']
170
cppflags += shlex.split(buildconfig.substs['WARNINGS_AS_ERRORS'])
171
env = get_config_defines(buildconfig)
172
js_path = re.sub(r"\.out\.h$", "", c_out.name) + ".js"
173
msgs = messages(msg_file)
174
with open(js_path, 'w') as js_out:
175
embed(cxx, pp_option, cppflags, msgs, sources, c_out, js_out, namespace, env)
176
177
178
def generate_selfhosted(c_out, msg_file, *inputs):
179
# Called from moz.build to embed selfhosted JS.
180
process_inputs('selfhosted', c_out, msg_file, inputs)
181
182
183
def generate_shellmoduleloader(c_out, msg_file, *inputs):
184
# Called from moz.build to embed shell module loader JS.
185
process_inputs('moduleloader', c_out, msg_file, inputs)