X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/4be4e30906bcb8ee30b4d189205cb70bad6707ce..81345200c95645a1b0d2635520f96ad55dfde63f:/generate-js-builtins diff --git a/generate-js-builtins b/generate-js-builtins new file mode 100644 index 0000000..613a207 --- /dev/null +++ b/generate-js-builtins @@ -0,0 +1,304 @@ +#!/usr/bin/python +# Copyright (C) 2014 Apple Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import filecmp +import fnmatch +import os +import re +import shutil +import sys +import datetime +import json + +copyrightText = """ * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */\n +""" + +generatorString = "/* Generated by %s do not hand edit. */\n" % os.path.basename(__file__) + +functionHeadRegExp = re.compile(r"function\s+\w+\s*\(.*?\)", re.MULTILINE | re.S) +functionNameRegExp = re.compile(r"function\s+(\w+)\s*\(", re.MULTILINE | re.S) +functionParameterFinder = re.compile(r"^function\s+(?:\w+)\s*\(((?:\s*\w+)?\s*(?:\s*,\s*\w+)*)?\)", re.MULTILINE | re.S) + +multilineCommentRegExp = re.compile(r"\/\*.*?\*\/", re.MULTILINE | re.S) +singleLineCommentRegExp = re.compile(r"\/\/.*?\n", re.MULTILINE | re.S) + +def getCopyright(source): + copyrightBlock = multilineCommentRegExp.findall(source)[0] + copyrightBlock = copyrightBlock[:copyrightBlock.index("Redistribution")] + copyRightLines = [] + + for line in copyrightBlock.split("\n"): + line = line.replace("/*", "") + line = line.replace("*/", "") + line = line.replace("*", "") + line = line.replace("Copyright", "") + line = line.replace("copyright", "") + line = line.replace("(C)", "") + line = line.replace("(c)", "") + line = line.strip() + if len(line) == 0: + continue + + copyRightLines.append(line) + + return list(set(copyRightLines)) + + + +def getFunctions(source): + + source = multilineCommentRegExp.sub("/**/", singleLineCommentRegExp.sub("//\n", source)) + + matches = [ f for f in functionHeadRegExp.finditer(source)] + functionBounds = [] + start = 0 + end = 0 + for match in matches: + start = match.start() + if start < end: + continue + end = match.end() + while source[end] != '{': + end = end + 1 + depth = 1 + end = end + 1 + while depth > 0: + if source[end] == '{': + depth = depth + 1 + elif source[end] == '}': + depth = depth - 1 + end = end + 1 + functionBounds.append((start, end)) + + functions = [source[start:end].strip() for (start, end) in functionBounds] + result = [] + for function in functions: + function = multilineCommentRegExp.sub("", function) + functionName = functionNameRegExp.findall(function)[0] + functionParameters = functionParameterFinder.findall(function)[0].split(',') + if len(functionParameters[0]) == 0: + functionParameters = [] + + result.append((functionName, function, functionParameters)) + return result + + +def generateCode(source): + inputFile = open(source, "r") + baseName = os.path.basename(source).replace(".js", "") + + source = "" + for line in inputFile: + source = source + line + + if sys.platform == "cygwin": + source = source.replace("\r\n", "\n") + return (baseName, getFunctions(source), getCopyright(source)) + +def mangleName(object, name): + qName = object + "." + name + mangledName = "" + i = 0 + while i < len(qName): + if qName[i] == '.': + mangledName = mangledName + qName[i + 1].upper() + i = i + 1 + else: + mangledName = mangledName + qName[i] + i = i + 1 + return mangledName + +builtins = [] + +baseName = sys.argv[-1] +builtin_definitions = sys.argv[1:-1] +(output_base, _) = os.path.splitext(sys.argv[-1]) + +copyrights = [] +for file in builtin_definitions: + if fnmatch.fnmatch(file, '*.js'): + (baseName, functions, objectCopyrights) = generateCode(file) + copyrights.extend(objectCopyrights) + builtins.append((baseName, functions)) + +copyrights = list(set(copyrights)) + +copyrightBody = "" +for copyright in copyrights: + copyrightBody = copyrightBody +" * Copyright (C) " + copyright + "\n" + +builtinsHeader = open(output_base + ".h.tmp", "w") +builtinsImplementation = open(output_base + ".cpp.tmp", "w") +copyrightText = "/*\n" + copyrightBody + copyrightText +builtinsHeader.write("""%s +%s + +#ifndef JSCBuiltins_H +#define JSCBuiltins_H + +namespace JSC { + +class FunctionExecutable; +class Identifier; +class JSGlobalObject; +class SourceCode; +class UnlinkedFunctionExecutable; +class VM; + +FunctionExecutable* createBuiltinExecutable(VM&, UnlinkedFunctionExecutable*, const SourceCode&); + +""" % (generatorString, copyrightText)) + +codeReferences = [] + +for (objectName, functions) in builtins: + print("Generating bindings for the %s builtin." % objectName) + builtinsHeader.write("/* %s functions */\n" % objectName) + for (name, implementation, _) in functions: + mangledName = mangleName(objectName, name) + mangledName = mangledName[0].lower() + mangledName[1:] + "Code" + codeReferences.append((mangledName, name, implementation)) + builtinsHeader.write("extern const char* s_%s;\n" % mangledName) + builtinsHeader.write("extern const int s_%sLength;\n" % mangledName) + builtinsHeader.write("\n") + builtinsHeader.write("#define JSC_FOREACH_%s_BUILTIN(macro) \\\n" % objectName.replace(".", "_").upper()) + for (name, implementation, arguments) in functions: + mangledName = mangleName(objectName, name) + builtinsHeader.write(" macro(%s, %s, %d) \\\n" % (name, mangledName, len(arguments))) + builtinsHeader.write("\n") + for (name, implementation, arguments) in functions: + builtinsHeader.write("#define JSC_BUILTIN_%s 1\n" % mangleName(objectName, name).upper()) + builtinsHeader.write("\n\n") +names = [] +builtinsHeader.write("#define JSC_FOREACH_BUILTIN(macro)\\\n") +for (codeReference, functionName, source) in codeReferences: + builtinsHeader.write(" macro(%s, %s, s_%sLength) \\\n" % (codeReference, functionName, codeReference)) + names.append(functionName) + +builtinsHeader.write("\n\n") +builtinsHeader.write("#define JSC_FOREACH_BUILTIN_FUNCTION_NAME(macro) \\\n") +for name in sorted(set(names)): + builtinsHeader.write(" macro(%s) \\\n" % name) +builtinsHeader.write(""" + +#define JSC_DECLARE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\ + FunctionExecutable* codeName##Generator(VM&); + +JSC_FOREACH_BUILTIN(JSC_DECLARE_BUILTIN_GENERATOR) +#undef JSC_DECLARE_BUILTIN_GENERATOR + +#define JSC_BUILTIN_EXISTS(name) defined JSC_BUILTIN_ ## name + +} + +#endif + +""") + +builtinsImplementation.write("""%s +%s + +#include "config.h" + +#include "JSCBuiltins.h" + +#include "BuiltinExecutables.h" +#include "Executable.h" +#include "JSCellInlines.h" +#include "VM.h" + +namespace JSC { + +""" % (generatorString, copyrightText)) + +for (codeReference, name, source) in codeReferences: + source = "(function " + source[source.index("("):] + ")" + lines = json.dumps(source)[1:-1].split("\\n") + sourceLength = len(source) + source = "" + for line in lines: + source = source + (" \"%s\\n\" \\\n" % line) + builtinsImplementation.write("const char* s_%s =\n%s;\n\n" % (codeReference, source)) + builtinsImplementation.write("const int s_%sLength = %d;\n\n" % (codeReference, sourceLength + 1)) # + 1 for \n + +builtinsImplementation.write(""" +FunctionExecutable* createBuiltinExecutable(VM& vm, UnlinkedFunctionExecutable* unlinkedExecutable, const SourceCode& source) +{ + unsigned lineCount = unlinkedExecutable->lineCount(); + unsigned startColumn = 1; + unsigned sourceLength = unlinkedExecutable->sourceLength(); + bool endColumnIsOnStartLine = !lineCount; + unsigned endColumnExcludingBraces = unlinkedExecutable->unlinkedBodyEndColumn() + (endColumnIsOnStartLine ? 0 : 1); + unsigned startOffset = unlinkedExecutable->startOffset(); + unsigned startOffsetExcludingOpenBrace = startOffset + 1; + unsigned endOffsetExcludingCloseBrace = startOffset + sourceLength - 1; + SourceCode bodySource(source.provider(), startOffsetExcludingOpenBrace, endOffsetExcludingCloseBrace, 0, startColumn); + return FunctionExecutable::create(vm, bodySource, unlinkedExecutable, 0, lineCount, startColumn, endColumnExcludingBraces, false); +} + +#define JSC_DEFINE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\ +FunctionExecutable* codeName##Generator(VM& vm) \\ +{ \\ + return createBuiltinExecutable(vm, vm.builtinExecutables()->codeName##Executable(), vm.builtinExecutables()->codeName##Source()); \\ +} + +JSC_FOREACH_BUILTIN(JSC_DEFINE_BUILTIN_GENERATOR) +#undef JSC_DEFINE_BUILTIN_GENERATOR +} + +""") + +builtinsHeader.close() +builtinsImplementation.close() + +if (not os.path.exists(output_base + ".h")) or (not filecmp.cmp(output_base + ".h.tmp", output_base + ".h", shallow=False)): + os.rename(output_base + ".h.tmp", output_base + ".h") +else: + os.remove(output_base + ".h.tmp") + +if (not os.path.exists(output_base + ".cpp")) or (not filecmp.cmp(output_base + ".cpp.tmp", output_base + ".cpp", shallow=False)): + os.rename(output_base + ".cpp.tmp", output_base + ".cpp") +else: + os.remove(output_base + ".cpp.tmp")