Introducing construct ability into JS executables
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Jul 2015 02:36:20 +0000 (02:36 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Jul 2015 02:36:20 +0000 (02:36 +0000)
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)
    {
        ...
    }

* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* builtins/BuiltinExecutables.cpp:
(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):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@187205 268f45cc-cd09-0410-ab3c-d52691b4dbfc

21 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/builtins/BuiltinExecutables.cpp
Source/JavaScriptCore/builtins/BuiltinExecutables.h
Source/JavaScriptCore/builtins/Iterator.prototype.js
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/generate-js-builtins
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/runtime/CodeCache.cpp
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Source/JavaScriptCore/runtime/ConstructAbility.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/Executable.h
Source/JavaScriptCore/runtime/JSFunction.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/tests/stress/non-constructors.js [new file with mode: 0644]

index 1678535..b9db5db 100644 (file)
@@ -1,3 +1,85 @@
+2015-07-22  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        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)
+            {
+                ...
+            }
+
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * builtins/BuiltinExecutables.cpp:
+        (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):
+
 2015-07-22  Csaba Osztrogon√°c  <ossy@webkit.org>
 
         [JSC] Enable exception fuzzing for GCC too
index 3a5549c..9523d70 100644 (file)
     <ClInclude Include="..\runtime\ConsolePrototype.h" />
     <ClInclude Include="..\runtime\ConsoleTypes.h" />
     <ClInclude Include="..\runtime\ConstantMode.h" />
+    <ClInclude Include="..\runtime\ConstructAbility.h" />
     <ClInclude Include="..\runtime\ConstructData.h" />
     <ClInclude Include="..\runtime\ControlFlowProfiler.h" />
     <ClInclude Include="..\runtime\CustomGetterSetter.h" />
index 170cb49..21d67c0 100644 (file)
     <ClInclude Include="..\runtime\ConsoleTypes.h">
       <Filter>runtime</Filter>
     </ClInclude>
+    <ClInclude Include="..\runtime\ConstructAbility.h">
+      <Filter>runtime</Filter>
+    </ClInclude>
     <ClInclude Include="..\runtime\ConstructData.h">
       <Filter>runtime</Filter>
     </ClInclude>
index adde524..48622eb 100644 (file)
                E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */ = {isa = PBXBuildFile; fileRef = E124A8F50E555775003091F1 /* OpaqueJSString.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E124A8F60E555775003091F1 /* OpaqueJSString.cpp */; };
                E18E3A590DF9278C00D90B34 /* VM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E18E3A570DF9278C00D90B34 /* VM.cpp */; };
+               E354622B1B6065D100545386 /* ConstructAbility.h in Headers */ = {isa = PBXBuildFile; fileRef = E354622A1B6065D100545386 /* ConstructAbility.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E49DC16B12EF293E00184A1F /* SourceProviderCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E49DC15512EF277200184A1F /* SourceProviderCache.cpp */; };
                E49DC16C12EF294E00184A1F /* SourceProviderCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E49DC15112EF272200184A1F /* SourceProviderCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E49DC16D12EF295300184A1F /* SourceProviderCacheItem.h in Headers */ = {isa = PBXBuildFile; fileRef = E49DC14912EF261A00184A1F /* SourceProviderCacheItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E178636C0D9BEEC300D74E75 /* InitializeThreading.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InitializeThreading.cpp; sourceTree = "<group>"; };
                E18E3A560DF9278C00D90B34 /* VM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = VM.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
                E18E3A570DF9278C00D90B34 /* VM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = VM.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+               E354622A1B6065D100545386 /* ConstructAbility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstructAbility.h; sourceTree = "<group>"; };
                E49DC14912EF261A00184A1F /* SourceProviderCacheItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SourceProviderCacheItem.h; sourceTree = "<group>"; };
                E49DC15112EF272200184A1F /* SourceProviderCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SourceProviderCache.h; sourceTree = "<group>"; };
                E49DC15512EF277200184A1F /* SourceProviderCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SourceProviderCache.cpp; sourceTree = "<group>"; };
                                A5FD0071189B038C00633231 /* ConsoleTypes.h */,
                                0F978B3A1AAEA71D007C7369 /* ConstantMode.cpp */,
                                0FFC99D0184EC8AD009C10AB /* ConstantMode.h */,
+                               E354622A1B6065D100545386 /* ConstructAbility.h */,
                                BCA62DFF0E2826310004F30D /* ConstructData.cpp */,
                                BC8F3CCF0DAF17BA00577A80 /* ConstructData.h */,
                                52B717B41A0597E1007AF4F3 /* ControlFlowProfiler.cpp */,
                                0F6B1CC41862C47800845D97 /* FTLRegisterAtOffset.h in Headers */,
                                0FCEFAAC1804C13E00472CE4 /* FTLSaveRestore.h in Headers */,
                                0F25F1B2181635F300522F39 /* FTLSlowPathCall.h in Headers */,
+                               E354622B1B6065D100545386 /* ConstructAbility.h in Headers */,
                                0F25F1B4181635F300522F39 /* FTLSlowPathCallKey.h in Headers */,
                                0F9D339B1803ADB70073C2BC /* FTLStackMaps.h in Headers */,
                                0FEA0A12170513DB00BB722C /* FTLState.h in Headers */,
index be224dd..3615fa2 100644 (file)
@@ -52,15 +52,15 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createDefaultConstructor(Constru
     case ConstructorKind::None:
         break;
     case ConstructorKind::Base:
-        return createExecutableInternal(makeSource(baseConstructorCode), name, constructorKind);
+        return createExecutableInternal(makeSource(baseConstructorCode), name, constructorKind, ConstructAbility::CanConstruct);
     case ConstructorKind::Derived:
-        return createExecutableInternal(makeSource(derivedConstructorCode), name, constructorKind);
+        return createExecutableInternal(makeSource(derivedConstructorCode), name, constructorKind, ConstructAbility::CanConstruct);
     }
     ASSERT_NOT_REACHED();
     return nullptr;
 }
 
-UnlinkedFunctionExecutable* BuiltinExecutables::createExecutableInternal(const SourceCode& source, const Identifier& name, ConstructorKind constructorKind)
+UnlinkedFunctionExecutable* BuiltinExecutables::createExecutableInternal(const SourceCode& source, const Identifier& name, ConstructorKind constructorKind, ConstructAbility constructAbility)
 {
     JSTextPosition positionBeforeLastNewline;
     ParserError error;
@@ -103,7 +103,7 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createExecutableInternal(const S
     }
     body->overrideName(name);
     VariableEnvironment dummyTDZVariables;
-    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&m_vm, source, body, kind, dummyTDZVariables, WTF::move(sourceOverride));
+    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&m_vm, source, body, kind, constructAbility, dummyTDZVariables, WTF::move(sourceOverride));
     functionExecutable->m_nameValue.set(m_vm, functionExecutable, jsString(&m_vm, name.string()));
     return functionExecutable;
 }
@@ -117,7 +117,7 @@ void BuiltinExecutables::finalize(Handle<Unknown>, void* context)
 UnlinkedFunctionExecutable* BuiltinExecutables::name##Executable() \
 {\
     if (!m_##name##Executable)\
-        m_##name##Executable = Weak<UnlinkedFunctionExecutable>(createBuiltinExecutable(m_##name##Source, m_vm.propertyNames->builtinNames().functionName##PublicName()), this, &m_##name##Executable);\
+        m_##name##Executable = Weak<UnlinkedFunctionExecutable>(createBuiltinExecutable(m_##name##Source, m_vm.propertyNames->builtinNames().functionName##PublicName(), s_##name##ConstructAbility), this, &m_##name##Executable);\
     return m_##name##Executable.get();\
 }
 JSC_FOREACH_BUILTIN(DEFINE_BUILTIN_EXECUTABLES)
index f0d5f4e..4e43222 100644 (file)
@@ -57,11 +57,11 @@ private:
 
     VM& m_vm;
 
-    UnlinkedFunctionExecutable* createBuiltinExecutable(const SourceCode& code, const Identifier& name)
+    UnlinkedFunctionExecutable* createBuiltinExecutable(const SourceCode& code, const Identifier& name, ConstructAbility constructAbility)
     {
-        return createExecutableInternal(code, name, ConstructorKind::None);
+        return createExecutableInternal(code, name, ConstructorKind::None, constructAbility);
     }
-    UnlinkedFunctionExecutable* createExecutableInternal(const SourceCode&, const Identifier&, ConstructorKind);
+    UnlinkedFunctionExecutable* createExecutableInternal(const SourceCode&, const Identifier&, ConstructorKind, ConstructAbility);
 
 #define DECLARE_BUILTIN_SOURCE_MEMBERS(name, functionName, length)\
     SourceCode m_##name##Source; \
index dc72a64..1e9b98c 100644 (file)
@@ -23,7 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-function SymbolIterator()
+function symbolIterator()
 {
     'use strict';
     return this;
index e053dad..6524998 100644 (file)
@@ -80,7 +80,7 @@ static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(
     return result;
 }
 
-UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, RefPtr<SourceProvider>&& sourceOverride, FunctionBodyNode* node, UnlinkedFunctionKind kind, VariableEnvironment& parentScopeTDZVariables)
+UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, RefPtr<SourceProvider>&& sourceOverride, FunctionBodyNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, VariableEnvironment& parentScopeTDZVariables)
     : Base(*vm, structure)
     , m_name(node->ident())
     , m_inferredName(node->inferredName())
@@ -101,6 +101,7 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct
     , m_isInStrictContext(node->isInStrictContext())
     , m_hasCapturedVariables(false)
     , m_isBuiltinFunction(kind == UnlinkedBuiltinFunction)
+    , m_constructAbility(static_cast<unsigned>(constructAbility))
     , m_constructorKind(static_cast<unsigned>(node->constructorKind()))
     , m_functionMode(node->functionMode())
 {
index 75a966c..a289d24 100644 (file)
@@ -29,6 +29,7 @@
 #include "BytecodeConventions.h"
 #include "CodeSpecializationKind.h"
 #include "CodeType.h"
+#include "ConstructAbility.h"
 #include "ExpressionRangeInfo.h"
 #include "HandlerInfo.h"
 #include "Identifier.h"
@@ -107,10 +108,10 @@ public:
     typedef JSCell Base;
     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
-    static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionBodyNode* node, UnlinkedFunctionKind unlinkedFunctionKind, VariableEnvironment& parentScopeTDZVariables, RefPtr<SourceProvider>&& sourceOverride = nullptr)
+    static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionBodyNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, VariableEnvironment& parentScopeTDZVariables, RefPtr<SourceProvider>&& sourceOverride = nullptr)
     {
         UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm->heap))
-            UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, WTF::move(sourceOverride), node, unlinkedFunctionKind, parentScopeTDZVariables);
+            UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, WTF::move(sourceOverride), node, unlinkedFunctionKind, constructAbility, parentScopeTDZVariables);
         instance->finishCreation(*vm);
         return instance;
     }
@@ -162,11 +163,12 @@ public:
     static void destroy(JSCell*);
 
     bool isBuiltinFunction() const { return m_isBuiltinFunction; }
+    ConstructAbility constructAbility() const { return static_cast<ConstructAbility>(m_constructAbility); }
     bool isClassConstructorFunction() const { return constructorKind() != ConstructorKind::None; }
     const VariableEnvironment* parentScopeTDZVariables() const { return &m_parentScopeTDZVariables; }
 
 private:
-    UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, RefPtr<SourceProvider>&& sourceOverride, FunctionBodyNode*, UnlinkedFunctionKind, VariableEnvironment&);
+    UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, RefPtr<SourceProvider>&& sourceOverride, FunctionBodyNode*, UnlinkedFunctionKind, ConstructAbility, VariableEnvironment&);
     WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForCall;
     WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForConstruct;
 
@@ -193,6 +195,7 @@ private:
     unsigned m_isInStrictContext : 1;
     unsigned m_hasCapturedVariables : 1;
     unsigned m_isBuiltinFunction : 1;
+    unsigned m_constructAbility: 1;
     unsigned m_constructorKind : 2;
     unsigned m_functionMode : 1; // FunctionMode
 
index 748b90e..6d7ce7d 100644 (file)
@@ -701,7 +701,13 @@ namespace JSC {
         {
             VariableEnvironment variablesUnderTDZ;
             getVariablesUnderTDZ(variablesUnderTDZ);
-            return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), body, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, variablesUnderTDZ);
+
+            FunctionParseMode parseMode = body->parseMode();
+            ConstructAbility constructAbility = ConstructAbility::CanConstruct;
+            if (parseMode == GetterMode || parseMode == SetterMode || parseMode == ArrowFunctionMode || (parseMode == MethodMode && body->constructorKind() == ConstructorKind::None))
+                constructAbility = ConstructAbility::CannotConstruct;
+
+            return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), body, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, variablesUnderTDZ);
         }
 
         void getVariablesUnderTDZ(VariableEnvironment&);
index 446b497..9647163 100644 (file)
@@ -64,9 +64,10 @@ copyrightText = """ *
 
 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+)*)?\s*\)", re.MULTILINE | re.S)
+functionHeadRegExp = re.compile(r"(?:function|constructor)\s+\w+\s*\(.*?\)", re.MULTILINE | re.S)
+functionNameRegExp = re.compile(r"(?:function|constructor)\s+(\w+)\s*\(", re.MULTILINE | re.S)
+functionIsConstructorRegExp = re.compile(r"^constructor", re.MULTILINE | re.S)
+functionParameterFinder = re.compile(r"^(?:function|constructor)\s+(?:\w+)\s*\(((?:\s*\w+)?\s*(?:\s*,\s*\w+)*)?\s*\)", re.MULTILINE | re.S)
 
 multilineCommentRegExp = re.compile(r"\/\*.*?\*\/", re.MULTILINE | re.S)
 singleLineCommentRegExp = re.compile(r"\/\/.*?\n", re.MULTILINE | re.S)
@@ -92,7 +93,27 @@ def getCopyright(source):
     
     return list(set(copyRightLines))
 
-
+class Function(object):
+    def __init__(self, name, source, isConstructor, parameters):
+        self.name = name
+        self.source = source
+        self.isConstructor = isConstructor
+        self.parameters = parameters
+
+    def mangleName(self, object):
+        qName = object + "." + self.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
+        if self.isConstructor:
+            mangledName = mangledName + "Constructor"
+        return mangledName
 
 def getFunctions(source):
 
@@ -124,13 +145,14 @@ def getFunctions(source):
     for function in functions:
         function = multilineCommentRegExp.sub("", function)
         functionName = functionNameRegExp.findall(function)[0]
+        functionIsConstructor = functionIsConstructorRegExp.match(function) != None
         functionParameters = functionParameterFinder.findall(function)[0].split(',')
         if len(functionParameters[0]) == 0:
             functionParameters = []
-            
-        result.append((functionName, function, functionParameters))
+
+        result.append(Function(functionName, function, functionIsConstructor, functionParameters))
     return result
-        
+
 
 def generateCode(source):
     inputFile = open(source, "r")
@@ -144,19 +166,6 @@ def generateCode(source):
         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 = []
 copyrights = []
 (output_base, _) = os.path.splitext(args.output)
@@ -186,6 +195,8 @@ builtinsHeader.write("""%s
 #ifndef JSCBuiltins_H
 #define JSCBuiltins_H
 
+#include "ConstructAbility.h"
+
 namespace JSC {
 
 class FunctionExecutable;
@@ -204,26 +215,28 @@ 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)
+    for function in functions:
+        name = function.name
+        mangledName = function.mangleName(objectName)
         mangledName = mangledName[0].lower() + mangledName[1:] + "Code"
-        codeReferences.append((mangledName, name, implementation))
+        codeReferences.append((mangledName, function))
         builtinsHeader.write("extern const char* s_%s;\n" % mangledName)
         builtinsHeader.write("extern const int s_%sLength;\n" % mangledName)
+        builtinsHeader.write("extern const ConstructAbility s_%sConstructAbility;\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)))
+    for function in functions:
+        mangledName = function.mangleName(objectName)
+        builtinsHeader.write("    macro(%s, %s, %d) \\\n" % (function.name, mangledName, len(function.parameters)))
     builtinsHeader.write("\n")
-    for (name, implementation, arguments) in functions:
-        builtinsHeader.write("#define JSC_BUILTIN_%s 1\n" % mangleName(objectName, name).upper())
+    for function in functions:
+        builtinsHeader.write("#define JSC_BUILTIN_%s 1\n" % function.mangleName(objectName).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)
+for (codeReference, function) in codeReferences:
+    builtinsHeader.write("    macro(%s, %s, s_%sLength) \\\n" % (codeReference, function.name, codeReference))
+    names.append(function.name)
 
 builtinsHeader.write("\n\n")
 builtinsHeader.write("#define JSC_FOREACH_BUILTIN_FUNCTION_NAME(macro) \\\n")
@@ -253,6 +266,7 @@ builtinsImplementation.write("""%s
 #include "JSCBuiltins.h"
 
 #include "BuiltinExecutables.h"
+#include "ConstructAbility.h"
 #include "Executable.h"
 #include "JSCellInlines.h"
 #include "VM.h"
@@ -261,7 +275,8 @@ namespace JSC {
 
 """  % (generatorString, copyrightText))
 
-for (codeReference, name, source) in codeReferences:
+for (codeReference, function) in codeReferences:
+    source = function.source
     source = "(function " + source[source.index("("):] + ")"
     lines = json.dumps(source)[1:-1].split("\\n")
     sourceLength = len(source)
@@ -270,6 +285,10 @@ for (codeReference, name, source) in codeReferences:
         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
+    constructAbility = "ConstructAbility::CannotConstruct"
+    if function.isConstructor:
+        constructAbility = "ConstructAbility::CanConstruct"
+    builtinsImplementation.write("const ConstructAbility s_%sConstructAbility = %s;\n\n" % (codeReference, constructAbility)) # + 1 for \n
 
 builtinsImplementation.write("""
 #define JSC_DEFINE_BUILTIN_GENERATOR(codeName, functionName, argumentCount) \\
index 9d17441..31223a5 100644 (file)
@@ -783,7 +783,7 @@ inline char* linkFor(
     else {
         FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
 
-        if (!isCall(kind) && functionExecutable->isBuiltinFunction()) {
+        if (!isCall(kind) && functionExecutable->constructAbility() == ConstructAbility::CannotConstruct) {
             exec->vm().throwException(exec, createNotAConstructorError(exec, callee));
             return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress());
         }
@@ -848,7 +848,7 @@ inline char* virtualForWithFunction(
     if (UNLIKELY(!executable->hasJITCodeFor(kind))) {
         FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
 
-        if (!isCall(kind) && functionExecutable->isBuiltinFunction()) {
+        if (!isCall(kind) && functionExecutable->constructAbility() == ConstructAbility::CannotConstruct) {
             exec->vm().throwException(exec, createNotAConstructorError(exec, function));
             return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress());
         }
index 1934e57..f5da898 100644 (file)
@@ -1104,7 +1104,7 @@ inline SlowPathReturnType setUpCall(ExecState* execCallee, Instruction* pc, Code
     else {
         FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
 
-        if (!isCall(kind) && functionExecutable->isBuiltinFunction())
+        if (!isCall(kind) && functionExecutable->constructAbility() == ConstructAbility::CannotConstruct)
             LLINT_CALL_THROW(exec, createNotAConstructorError(exec, callee));
 
         JSObject* error = functionExecutable->prepareForExecution(execCallee, callee, scope, kind);
index 48a71c7..5b5c575 100644 (file)
@@ -1898,7 +1898,7 @@ template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(T
         } else {
             ParserFunctionInfo<TreeBuilder> methodInfo;
             bool isConstructor = !isStaticMethod && *ident == propertyNames.constructor;
-            failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, isStaticMethod ? NormalFunctionMode : MethodMode, false, isConstructor ? constructorKind : ConstructorKind::None, SuperBinding::Needed, methodStart, methodInfo, StandardFunctionParseType)), "Cannot parse this method");
+            failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, MethodMode, false, isConstructor ? constructorKind : ConstructorKind::None, SuperBinding::Needed, methodStart, methodInfo, StandardFunctionParseType)), "Cannot parse this method");
             failIfTrue(!ident || (declareVariable(ident) & DeclarationResult::InvalidStrictMode), "Cannot declare a method named '", methodInfo.name->impl(), "'");
             methodInfo.name = isConstructor ? className : ident;
 
index 0001d5c..485bab7 100644 (file)
@@ -174,7 +174,7 @@ UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& v
     body->setEndPosition(positionBeforeLastNewline);
     // The Function constructor only has access to global variables, so no variables will be under TDZ.
     VariableEnvironment emptyTDZVariables;
-    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, body, UnlinkedNormalFunction, emptyTDZVariables);
+    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, body, UnlinkedNormalFunction, ConstructAbility::CanConstruct, emptyTDZVariables);
     functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string()));
 
     m_sourceCode.addCache(key, SourceCodeValue(vm, functionExecutable, m_sourceCode.age()));
index fda5289..9b93987 100644 (file)
 
 #define JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(macro) \
     JSC_COMMON_BYTECODE_INTRINSICS_EACH_NAME(macro) \
-    macro(symbolIterator) \
     macro(iteratedObject) \
     macro(arrayIteratorNextIndex) \
     macro(arrayIterationKind) \
diff --git a/Source/JavaScriptCore/runtime/ConstructAbility.h b/Source/JavaScriptCore/runtime/ConstructAbility.h
new file mode 100644 (file)
index 0000000..3af880b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef ConstructAbility_h
+#define ConstructAbility_h
+
+namespace JSC {
+
+enum class ConstructAbility : unsigned {
+    CanConstruct,
+    CannotConstruct,
+};
+
+}
+
+#endif // ConstructAbility_h
index 8d87107..6ec112d 100644 (file)
@@ -630,6 +630,7 @@ public:
         
     FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); }
     bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); }
+    ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
     bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); }
     const Identifier& name() { return m_unlinkedExecutable->name(); }
     const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); }
index 1b8c407..0f7354e 100644 (file)
@@ -552,14 +552,16 @@ ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& construc
 {
     JSFunction* thisObject = jsCast<JSFunction*>(cell);
 
-    if (thisObject->isBuiltinFunction())
-        return ConstructTypeNone;
-
     if (thisObject->isHostFunction()) {
         constructData.native.function = thisObject->nativeConstructor();
         return ConstructTypeHost;
     }
-    constructData.js.functionExecutable = thisObject->jsExecutable();
+
+    FunctionExecutable* functionExecutable = thisObject->jsExecutable();
+    if (functionExecutable->constructAbility() == ConstructAbility::CannotConstruct)
+        return ConstructTypeNone;
+
+    constructData.js.functionExecutable = functionExecutable;
     constructData.js.scope = thisObject->scope();
     return ConstructTypeJS;
 }
index 419c1b2..043e938 100644 (file)
@@ -506,7 +506,7 @@ putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct
         GlobalPropertyInfo(vm.propertyNames->arrayIterationKindKeyPrivateName, jsNumber(ArrayIterateKey), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->arrayIterationKindValuePrivateName, jsNumber(ArrayIterateValue), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->arrayIterationKindKeyValuePrivateName, jsNumber(ArrayIterateKeyValue), DontEnum | DontDelete | ReadOnly),
-        GlobalPropertyInfo(vm.propertyNames->symbolIteratorPrivateName, Symbol::create(vm, static_cast<SymbolImpl&>(*vm.propertyNames->iteratorSymbol.impl())), DontEnum | DontDelete | ReadOnly),
+        GlobalPropertyInfo(vm.propertyNames->builtinNames().symbolIteratorPrivateName(), Symbol::create(vm, static_cast<SymbolImpl&>(*vm.propertyNames->iteratorSymbol.impl())), DontEnum | DontDelete | ReadOnly),
 #if ENABLE(PROMISES)
         GlobalPropertyInfo(vm.propertyNames->PromisePrivateName, m_promiseConstructor.get(), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->promisePendingPrivateName, jsNumber(static_cast<unsigned>(JSPromise::Status::Pending)), DontEnum | DontDelete | ReadOnly),
diff --git a/Source/JavaScriptCore/tests/stress/non-constructors.js b/Source/JavaScriptCore/tests/stress/non-constructors.js
new file mode 100644 (file)
index 0000000..32de719
--- /dev/null
@@ -0,0 +1,116 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+class ClassTest {
+    constructor() {
+    }
+
+    method() {
+    }
+
+    get getter() {
+        return 20;
+    }
+
+    set setter(name) {
+    }
+
+    static method() {
+    }
+
+    static get getter() {
+        return 20;
+    }
+
+    static set setter(name) {
+        return 20;
+    }
+};
+
+// Should not throw ('constructor' is a function).
+var test = new ClassTest();
+var test2 = new test.constructor();
+
+shouldThrow(() => {
+    new test.method();
+}, `TypeError: function is not a constructor (evaluating 'new test.method()')`);
+
+shouldThrow(() => {
+    var descriptor = Object.getOwnPropertyDescriptor(test.__proto__, 'getter');
+    new descriptor.get();
+}, `TypeError: function is not a constructor (evaluating 'new descriptor.get()')`);
+
+shouldThrow(() => {
+    var descriptor = Object.getOwnPropertyDescriptor(test.__proto__, 'setter');
+    new descriptor.set();
+}, `TypeError: function is not a constructor (evaluating 'new descriptor.set()')`);
+
+shouldThrow(() => {
+    new ClassTest.method();
+}, `TypeError: function is not a constructor (evaluating 'new ClassTest.method()')`);
+
+shouldThrow(() => {
+    var descriptor = Object.getOwnPropertyDescriptor(ClassTest, 'getter');
+    new descriptor.get();
+}, `TypeError: function is not a constructor (evaluating 'new descriptor.get()')`);
+
+shouldThrow(() => {
+    var descriptor = Object.getOwnPropertyDescriptor(ClassTest, 'setter');
+    new descriptor.set();
+}, `TypeError: function is not a constructor (evaluating 'new descriptor.set()')`);
+
+
+var test = {
+    method() {
+    },
+
+    get getter() {
+        return 20;
+    },
+
+    set setter(name) {
+    },
+
+    normal: function () {
+    },
+
+    constructor() {
+    }
+};
+
+shouldThrow(() => {
+    new test.method();
+}, `TypeError: function is not a constructor (evaluating 'new test.method()')`);
+
+shouldThrow(() => {
+    new test.constructor();
+}, `TypeError: function is not a constructor (evaluating 'new test.constructor()')`);
+
+shouldThrow(() => {
+    var descriptor = Object.getOwnPropertyDescriptor(test, 'getter');
+    new descriptor.get();
+}, `TypeError: function is not a constructor (evaluating 'new descriptor.get()')`);
+
+shouldThrow(() => {
+    var descriptor = Object.getOwnPropertyDescriptor(test, 'setter');
+    new descriptor.set();
+}, `TypeError: function is not a constructor (evaluating 'new descriptor.set()')`);
+
+new test.normal();
+
+shouldThrow(() => {
+    var arrow = () => { };
+    new arrow();
+}, `TypeError: function is not a constructor (evaluating 'new arrow()')`);