source: webkit/trunk/Source/JavaScriptCore/generate-js-builtins@ 187890

Last change on this file since 187890 was 187205, checked in by Yusuke Suzuki, 10 years ago

Introducing construct ability into JS executables
https://bugs.webkit.org/show_bug.cgi?id=147183

Reviewed by Geoffrey Garen.

Decouple the construct ability from the builtin functions.
Currently, all builtin functions are not constructors after r182995.
In that patch, when the given function is builtin JS function, we recognize it as the non-constructor function.

But, we need to relax it to implement some constructors in builtins JS.
By decoupling the construct ability from whether the function is builtin or not, we can provide

  1. constructors written in builtin JS
  2. non-constructors in normal JS functions

(1) is needed for Promise constructor.
And (2) is needed for method functions and arrow functions.

This patch introduces ConstructAbility into the unlinked function executables.
It holds whether the given JS function has the construct ability or not.
By leveraging this, this patch disables the construct ability of the method definitions, setters, getters and arrow functions.

And at the same time, this patch introduces the annotation for constructor in builtin JS.
We can define the function as follows,

constructor Promise(executor)
{

...

}

(JSC::BuiltinExecutables::createDefaultConstructor):
(JSC::BuiltinExecutables::createExecutableInternal):

  • builtins/BuiltinExecutables.h:
  • builtins/Iterator.prototype.js:

(symbolIterator):
(SymbolIterator): Deleted.

  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):

  • bytecode/UnlinkedCodeBlock.h:
  • bytecompiler/BytecodeGenerator.h:

(JSC::BytecodeGenerator::makeFunction):

  • generate-js-builtins:

(getCopyright):
(Function):
(Function.init):
(Function.mangleName):
(getFunctions):
(mangleName): Deleted.

  • jit/JITOperations.cpp:
  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::setUpCall):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseClass):

  • runtime/CodeCache.cpp:

(JSC::CodeCache::getFunctionExecutableFromGlobalCode):

  • runtime/CommonIdentifiers.h:
  • runtime/ConstructAbility.h: Copied from Source/JavaScriptCore/builtins/Iterator.prototype.js.
  • runtime/Executable.h:
  • runtime/JSFunction.cpp:

(JSC::JSFunction::getConstructData):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):

  • tests/stress/non-constructors.js: Added.

(shouldThrow):
(.prototype.method):
(.prototype.get getter):
(.prototype.set setter):
(.method):
(.get shouldThrow):
(.set shouldThrow):
(set var.test.get getter):
(set var.test.set setter):
(set var.test.normal):
(.set var):
(.set new):

File size: 11.8 KB
Line 
1#!/usr/bin/python
2# Copyright (C) 2014 Apple Inc. All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions
6# are met:
7# 1. Redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer.
9# 2. Redistributions in binary form must reproduce the above copyright
10# notice, this list of conditions and the following disclaimer in the
11# documentation and/or other materials provided with the distribution.
12#
13# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
25import argparse
26import filecmp
27import fnmatch
28import os
29import re
30import shutil
31import sys
32import datetime
33import json
34
35parser = argparse.ArgumentParser()
36parser.add_argument('input_file', nargs='*', help='Input JS files which builtins generated from')
37parser.add_argument('--input-directory', help='All JS files will be used as input from this directory.')
38parser.add_argument('--output', help='path to output cpp or h file')
39args = parser.parse_args()
40
41copyrightText = """ *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 *
51 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
52 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
54 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
55 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
58 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
59 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
61 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62 */\n
63"""
64
65generatorString = "/* Generated by %s do not hand edit. */\n" % os.path.basename(__file__)
66
67functionHeadRegExp = re.compile(r"(?:function|constructor)\s+\w+\s*\(.*?\)", re.MULTILINE | re.S)
68functionNameRegExp = re.compile(r"(?:function|constructor)\s+(\w+)\s*\(", re.MULTILINE | re.S)
69functionIsConstructorRegExp = re.compile(r"^constructor", re.MULTILINE | re.S)
70functionParameterFinder = re.compile(r"^(?:function|constructor)\s+(?:\w+)\s*\(((?:\s*\w+)?\s*(?:\s*,\s*\w+)*)?\s*\)", re.MULTILINE | re.S)
71
72multilineCommentRegExp = re.compile(r"\/\*.*?\*\/", re.MULTILINE | re.S)
73singleLineCommentRegExp = re.compile(r"\/\/.*?\n", re.MULTILINE | re.S)
74
75def getCopyright(source):
76 copyrightBlock = multilineCommentRegExp.findall(source)[0]
77 copyrightBlock = copyrightBlock[:copyrightBlock.index("Redistribution")]
78 copyRightLines = []
79
80 for line in copyrightBlock.split("\n"):
81 line = line.replace("/*", "")
82 line = line.replace("*/", "")
83 line = line.replace("*", "")
84 line = line.replace("Copyright", "")
85 line = line.replace("copyright", "")
86 line = line.replace("(C)", "")
87 line = line.replace("(c)", "")
88 line = line.strip()
89 if len(line) == 0:
90 continue
91
92 copyRightLines.append(line)
93
94 return list(set(copyRightLines))
95
96class Function(object):
97 def __init__(self, name, source, isConstructor, parameters):
98 self.name = name
99 self.source = source
100 self.isConstructor = isConstructor
101 self.parameters = parameters
102
103 def mangleName(self, object):
104 qName = object + "." + self.name
105 mangledName = ""
106 i = 0
107 while i < len(qName):
108 if qName[i] == '.':
109 mangledName = mangledName + qName[i + 1].upper()
110 i = i + 1
111 else:
112 mangledName = mangledName + qName[i]
113 i = i + 1
114 if self.isConstructor:
115 mangledName = mangledName + "Constructor"
116 return mangledName
117
118def getFunctions(source):
119
120 source = multilineCommentRegExp.sub("/**/", singleLineCommentRegExp.sub("//\n", source))
121
122 matches = [ f for f in functionHeadRegExp.finditer(source)]
123 functionBounds = []
124 start = 0
125 end = 0
126 for match in matches:
127 start = match.start()
128 if start < end:
129 continue
130 end = match.end()
131 while source[end] != '{':
132 end = end + 1
133 depth = 1
134 end = end + 1
135 while depth > 0:
136 if source[end] == '{':
137 depth = depth + 1
138 elif source[end] == '}':
139 depth = depth - 1
140 end = end + 1
141 functionBounds.append((start, end))
142
143 functions = [source[start:end].strip() for (start, end) in functionBounds]
144 result = []
145 for function in functions:
146 function = multilineCommentRegExp.sub("", function)
147 functionName = functionNameRegExp.findall(function)[0]
148 functionIsConstructor = functionIsConstructorRegExp.match(function) != None
149 functionParameters = functionParameterFinder.findall(function)[0].split(',')
150 if len(functionParameters[0]) == 0:
151 functionParameters = []
152
153 result.append(Function(functionName, function, functionIsConstructor, functionParameters))
154 return result
155
156
157def generateCode(source):
158 inputFile = open(source, "r")
159 baseName = os.path.basename(source).replace(".js", "")
160
161 source = ""
162 for line in inputFile:
163 source = source + line
164
165 if sys.platform == "cygwin":
166 source = source.replace("\r\n", "\n")
167 return (baseName, getFunctions(source), getCopyright(source))
168
169builtins = []
170copyrights = []
171(output_base, _) = os.path.splitext(args.output)
172
173if args.input_directory:
174 for file in os.listdir(args.input_directory):
175 args.input_file.append(os.path.join(args.input_directory, file))
176
177for file in args.input_file:
178 if fnmatch.fnmatch(file, '*.js'):
179 (baseName, functions, objectCopyrights) = generateCode(file)
180 copyrights.extend(objectCopyrights)
181 builtins.append((baseName, functions))
182
183copyrights = list(set(copyrights))
184
185copyrightBody = ""
186for copyright in copyrights:
187 copyrightBody = copyrightBody +" * Copyright (C) " + copyright + "\n"
188
189builtinsHeader = open(output_base + ".h.tmp", "w")
190builtinsImplementation = open(output_base + ".cpp.tmp", "w")
191copyrightText = "/*\n" + copyrightBody + copyrightText
192builtinsHeader.write("""%s
193%s
194
195#ifndef JSCBuiltins_H
196#define JSCBuiltins_H
197
198#include "ConstructAbility.h"
199
200namespace JSC {
201
202class FunctionExecutable;
203class Identifier;
204class JSGlobalObject;
205class SourceCode;
206class UnlinkedFunctionExecutable;
207class VM;
208
209FunctionExecutable* createBuiltinExecutable(VM&, UnlinkedFunctionExecutable*, const SourceCode&);
210
211""" % (generatorString, copyrightText))
212
213codeReferences = []
214
215for (objectName, functions) in builtins:
216 print("Generating bindings for the %s builtin." % objectName)
217 builtinsHeader.write("/* %s functions */\n" % objectName)
218 for function in functions:
219 name = function.name
220 mangledName = function.mangleName(objectName)
221 mangledName = mangledName[0].lower() + mangledName[1:] + "Code"
222 codeReferences.append((mangledName, function))
223 builtinsHeader.write("extern const char* s_%s;\n" % mangledName)
224 builtinsHeader.write("extern const int s_%sLength;\n" % mangledName)
225 builtinsHeader.write("extern const ConstructAbility s_%sConstructAbility;\n" % mangledName)
226 builtinsHeader.write("\n")
227 builtinsHeader.write("#define JSC_FOREACH_%s_BUILTIN(macro) \\\n" % objectName.replace(".", "_").upper())
228 for function in functions:
229 mangledName = function.mangleName(objectName)
230 builtinsHeader.write(" macro(%s, %s, %d) \\\n" % (function.name, mangledName, len(function.parameters)))
231 builtinsHeader.write("\n")
232 for function in functions:
233 builtinsHeader.write("#define JSC_BUILTIN_%s 1\n" % function.mangleName(objectName).upper())
234 builtinsHeader.write("\n\n")
235names = []
236builtinsHeader.write("#define JSC_FOREACH_BUILTIN(macro)\\\n")
237for (codeReference, function) in codeReferences:
238 builtinsHeader.write(" macro(%s, %s, s_%sLength) \\\n" % (codeReference, function.name, codeReference))
239 names.append(function.name)
240
241builtinsHeader.write("\n\n")
242builtinsHeader.write("#define JSC_FOREACH_BUILTIN_FUNCTION_NAME(macro) \\\n")
243for name in sorted(set(names)):
244 builtinsHeader.write(" macro(%s) \\\n" % name)
245builtinsHeader.write("""
246
247#define JSC_DECLARE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\
248 FunctionExecutable* codeName##Generator(VM&);
249
250JSC_FOREACH_BUILTIN(JSC_DECLARE_BUILTIN_GENERATOR)
251#undef JSC_DECLARE_BUILTIN_GENERATOR
252
253#define JSC_BUILTIN_EXISTS(name) defined JSC_BUILTIN_ ## name
254
255}
256
257#endif
258
259""")
260
261builtinsImplementation.write("""%s
262%s
263
264#include "config.h"
265
266#include "JSCBuiltins.h"
267
268#include "BuiltinExecutables.h"
269#include "ConstructAbility.h"
270#include "Executable.h"
271#include "JSCellInlines.h"
272#include "VM.h"
273
274namespace JSC {
275
276""" % (generatorString, copyrightText))
277
278for (codeReference, function) in codeReferences:
279 source = function.source
280 source = "(function " + source[source.index("("):] + ")"
281 lines = json.dumps(source)[1:-1].split("\\n")
282 sourceLength = len(source)
283 source = ""
284 for line in lines:
285 source = source + (" \"%s\\n\" \\\n" % line)
286 builtinsImplementation.write("const char* s_%s =\n%s;\n\n" % (codeReference, source))
287 builtinsImplementation.write("const int s_%sLength = %d;\n\n" % (codeReference, sourceLength + 1)) # + 1 for \n
288 constructAbility = "ConstructAbility::CannotConstruct"
289 if function.isConstructor:
290 constructAbility = "ConstructAbility::CanConstruct"
291 builtinsImplementation.write("const ConstructAbility s_%sConstructAbility = %s;\n\n" % (codeReference, constructAbility)) # + 1 for \n
292
293builtinsImplementation.write("""
294#define JSC_DEFINE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\
295FunctionExecutable* codeName##Generator(VM& vm) \\
296{ \\
297 return vm.builtinExecutables()->codeName##Executable()->link(vm, vm.builtinExecutables()->codeName##Source()); \\
298}
299
300JSC_FOREACH_BUILTIN(JSC_DEFINE_BUILTIN_GENERATOR)
301#undef JSC_DEFINE_BUILTIN_GENERATOR
302}
303
304""")
305
306builtinsHeader.close()
307builtinsImplementation.close()
308
309if (not os.path.exists(output_base + ".h")) or (not filecmp.cmp(output_base + ".h.tmp", output_base + ".h", shallow=False)):
310 if (os.path.exists(output_base + ".h")):
311 os.remove(output_base + ".h")
312 os.rename(output_base + ".h.tmp", output_base + ".h")
313else:
314 os.remove(output_base + ".h.tmp")
315
316if (not os.path.exists(output_base + ".cpp")) or (not filecmp.cmp(output_base + ".cpp.tmp", output_base + ".cpp", shallow=False)):
317 if (os.path.exists(output_base + ".cpp")):
318 os.remove(output_base + ".cpp")
319 os.rename(output_base + ".cpp.tmp", output_base + ".cpp")
320else:
321 os.remove(output_base + ".cpp.tmp")
Note: See TracBrowser for help on using the repository browser.