Bug 1059908 - Introduce a CONSTRUCTOR flag and make getter/setter/method non-constructable. r=efaust
authorTom Schuster <evilpies@gmail.com>
Fri, 15 May 2015 20:53:03 +0200
changeset 244122 9f7b7d427d1c
parent 244121 2fd7da3aa49a
child 244123 fe22c89a36d5
push id28766
push userphilringnalda@gmail.com
push dateSat, 16 May 2015 15:50:57 +0000
treeherdermozilla-central@e00b8970afbd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1059908
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1059908 - Introduce a CONSTRUCTOR flag and make getter/setter/method non-constructable. r=efaust
js/src/asmjs/AsmJSLink.cpp
js/src/frontend/Parser.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/MCallOptimize.cpp
js/src/jit/MacroAssembler.cpp
js/src/jit/VMFunctions.cpp
js/src/jsapi.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsobj.cpp
js/src/shell/js.cpp
js/src/tests/ecma_6/Class/methodInstallation.js
js/src/tests/ecma_6/Object/accessor-non-constructor.js
js/src/tests/ecma_6/Object/method-non-constructor.js
js/src/tests/ecma_6/TypedArray/of.js
js/src/vm/Interpreter.cpp
js/src/vm/SelfHosting.cpp
--- a/js/src/asmjs/AsmJSLink.cpp
+++ b/js/src/asmjs/AsmJSLink.cpp
@@ -830,17 +830,17 @@ HandleDynamicLinkFailure(JSContext* cx, 
     }
 
     uint32_t begin = module.srcBodyStart();  // starts right after 'use asm'
     uint32_t end = module.srcEndBeforeCurly();
     Rooted<JSFlatString*> src(cx, module.scriptSource()->substringDontDeflate(cx, begin, end));
     if (!src)
         return false;
 
-    RootedFunction fun(cx, NewScriptedFunction(cx, 0, JSFunction::INTERPRETED,
+    RootedFunction fun(cx, NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL,
                                                name, gc::AllocKind::FUNCTION,
                                                TenuredObject));
     if (!fun)
         return false;
 
     AutoNameVector formals(cx);
     if (!formals.reserve(3))
         return false;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1235,17 +1235,17 @@ Parser<ParseHandler>::newFunction(Handle
         break;
       case Getter:
         flags = JSFunction::INTERPRETED_GETTER;
         break;
       case Setter:
         flags = JSFunction::INTERPRETED_SETTER;
         break;
       default:
-        flags = JSFunction::INTERPRETED;
+        flags = JSFunction::INTERPRETED_NORMAL;
         break;
     }
 
     fun = NewFunctionWithProto(context, nullptr, 0, flags, NullPtr(), atom, proto,
                                allocKind, TenuredObject);
     if (!fun)
         return nullptr;
     if (options().selfHostingMode)
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -10124,17 +10124,17 @@ TryAttachCallStub(JSContext* cx, ICCall_
 
     if (fun->hasScript()) {
         // Never attach optimized scripted call stubs for JSOP_FUNAPPLY.
         // MagicArguments may escape the frame through them.
         if (op == JSOP_FUNAPPLY)
             return true;
 
         // If callee is not an interpreted constructor, we have to throw.
-        if (constructing && !fun->isInterpretedConstructor())
+        if (constructing && !fun->isConstructor())
             return true;
 
         if (!fun->hasJITCode()) {
             // Don't treat this as an unoptimizable case, as we'll add a stub
             // when the callee becomes hot.
             *handled = true;
             return true;
         }
@@ -10222,17 +10222,17 @@ TryAttachCallStub(JSContext* cx, ICCall_
         if (!newStub)
             return false;
 
         stub->addNewStub(newStub);
         *handled = true;
         return true;
     }
 
-    if (fun->isNative() && (!constructing || (constructing && fun->isNativeConstructor()))) {
+    if (fun->isNative() && (!constructing || (constructing && fun->isConstructor()))) {
         // Generalized native call stubs are not here yet!
         MOZ_ASSERT(!stub->nativeStubsAreGeneralized());
 
         // Check for JSOP_FUNAPPLY
         if (op == JSOP_FUNAPPLY) {
             if (fun->native() == fun_apply)
                 return TryAttachFunApplyStub(cx, stub, script, pc, thisv, argc, vp + 2, handled);
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3039,17 +3039,17 @@ CodeGenerator::visitCallKnown(LCallKnown
     DebugOnly<JSFunction*> target = call->getSingleTarget();
     Label end, uncompiled;
 
     // Native single targets are handled by LCallNative.
     MOZ_ASSERT(!target->isNative());
     // Missing arguments must have been explicitly appended by the IonBuilder.
     MOZ_ASSERT(target->nargs() <= call->mir()->numStackArgs() - 1);
 
-    MOZ_ASSERT_IF(call->mir()->isConstructing(), target->isInterpretedConstructor());
+    MOZ_ASSERT_IF(call->mir()->isConstructing(), target->isConstructor());
 
     masm.checkStackAlignment();
 
     // The calleereg is known to be a non-native function, but might point to
     // a LazyScript instead of a JSScript.
     masm.branchIfFunctionHasNoScript(calleereg, &uncompiled);
 
     // Knowing that calleereg is a non-native function, load the JSScript.
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -458,17 +458,17 @@ IonBuilder::canInlineTarget(JSFunction* 
     }
 
     if (!target->hasScript()) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineLazy);
         return DontInline(nullptr, "Lazy script");
     }
 
     JSScript* inlineScript = target->nonLazyScript();
-    if (callInfo.constructing() && !target->isInterpretedConstructor()) {
+    if (callInfo.constructing() && !target->isConstructor()) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineNotConstructor);
         return DontInline(inlineScript, "Callee is not a constructor");
     }
 
     AnalysisMode analysisMode = info().analysisMode();
     if (!CanIonCompile(inlineScript, analysisMode)) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineDisabledIon);
         return DontInline(inlineScript, "Disabled Ion compilation");
@@ -5889,17 +5889,17 @@ IonBuilder::createThis(JSFunction* targe
 
         MCreateThis* createThis = MCreateThis::New(alloc(), callee);
         current->add(createThis);
         return createThis;
     }
 
     // Native constructors build the new Object themselves.
     if (target->isNative()) {
-        if (!target->isNativeConstructor())
+        if (!target->isConstructor())
             return nullptr;
 
         MConstant* magic = MConstant::New(alloc(), MagicValue(JS_IS_CONSTRUCTING));
         current->add(magic);
         return magic;
     }
 
     // Try baking in the prototype.
@@ -6339,18 +6339,17 @@ DOMCallNeedsBarrier(const JSJitInfo* jit
     return MIRTypeFromValueType(jitinfo->returnType()) != types->getKnownMIRType();
 }
 
 bool
 IonBuilder::makeCall(JSFunction* target, CallInfo& callInfo)
 {
     // Constructor calls to non-constructors should throw. We don't want to use
     // CallKnown in this case.
-    MOZ_ASSERT_IF(callInfo.constructing() && target,
-                  target->isInterpretedConstructor() || target->isNativeConstructor());
+    MOZ_ASSERT_IF(callInfo.constructing() && target, target->isConstructor());
 
     MCall* call = makeCallHelper(target, callInfo);
     if (!call)
         return false;
 
     current->push(call);
     if (call->isEffectful() && !resumeAfter(call))
         return false;
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -2740,19 +2740,17 @@ IonBuilder::inlineBoundFunction(CallInfo
     if (!target->getBoundFunctionTarget()->is<JSFunction>())
         return InliningStatus_NotInlined;
 
     JSFunction* scriptedTarget = &(target->getBoundFunctionTarget()->as<JSFunction>());
 
     // Don't optimize if we're constructing and the callee is not a
     // constructor, so that CallKnown does not have to handle this case
     // (it should always throw).
-    if (nativeCallInfo.constructing() && !scriptedTarget->isInterpretedConstructor() &&
-        !scriptedTarget->isNativeConstructor())
-    {
+    if (nativeCallInfo.constructing() && !scriptedTarget->isConstructor()) {
         return InliningStatus_NotInlined;
     }
 
     if (gc::IsInsideNursery(scriptedTarget))
         return InliningStatus_NotInlined;
 
     for (size_t i = 0; i < target->getBoundFunctionArgumentCount(); i++) {
         const Value val = target->getBoundFunctionArgument(i);
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -2382,61 +2382,24 @@ MacroAssembler::link(JitCode* code)
 void
 MacroAssembler::branchIfNotInterpretedConstructor(Register fun, Register scratch, Label* label)
 {
     // 16-bit loads are slow and unaligned 32-bit loads may be too so
     // perform an aligned 32-bit load and adjust the bitmask accordingly.
     MOZ_ASSERT(JSFunction::offsetOfNargs() % sizeof(uint32_t) == 0);
     MOZ_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2);
 
-    // Emit code for the following test:
-    //
-    // bool isInterpretedConstructor() const {
-    //     return isInterpreted() && !isFunctionPrototype() && !isArrow() &&
-    //         (!isSelfHostedBuiltin() || isSelfHostedConstructor());
-    // }
-
     // First, ensure it's a scripted function.
     load32(Address(fun, JSFunction::offsetOfNargs()), scratch);
     int32_t bits = IMM32_16ADJ(JSFunction::INTERPRETED);
     branchTest32(Assembler::Zero, scratch, Imm32(bits), label);
 
-    // Common case: if IS_FUN_PROTO, ARROW and SELF_HOSTED are not set,
-    // the function is an interpreted constructor and we're done.
-    Label done, moreChecks;
-
-    // Start with the easy ones. Check IS_FUN_PROTO and SELF_HOSTED.
-    bits = IMM32_16ADJ( (JSFunction::IS_FUN_PROTO | JSFunction::SELF_HOSTED) );
-    branchTest32(Assembler::NonZero, scratch, Imm32(bits), &moreChecks);
-
-    // Check !isArrow()
-    bits = IMM32_16ADJ(JSFunction::FUNCTION_KIND_MASK);
-    and32(Imm32(bits), scratch);
-
-    bits = IMM32_16ADJ(JSFunction::ARROW_KIND);
-    branch32(Assembler::NotEqual, scratch, Imm32(bits), &done);
-
-    // Reload the smashed flags and nargs for more checks.
-    load32(Address(fun, JSFunction::offsetOfNargs()), scratch);
-
-    {
-        bind(&moreChecks);
-        // The callee is either Function.prototype, an arrow function or
-        // self-hosted. None of these are constructible, except self-hosted
-        // constructors, so branch to |label| if SELF_HOSTED_CTOR is not set.
-        bits = IMM32_16ADJ(JSFunction::SELF_HOSTED_CTOR);
-        branchTest32(Assembler::Zero, scratch, Imm32(bits), label);
-
-#ifdef DEBUG
-        bits = IMM32_16ADJ(JSFunction::IS_FUN_PROTO);
-        branchTest32(Assembler::Zero, scratch, Imm32(bits), &done);
-        assumeUnreachable("Function.prototype should not have the SELF_HOSTED_CTOR flag");
-#endif
-    }
-    bind(&done);
+    // Check if the CONSTRUCTOR bit is set.
+    bits = IMM32_16ADJ(JSFunction::CONSTRUCTOR);
+    branchTest32(Assembler::Zero, scratch, Imm32(bits), label);
 }
 
 void
 MacroAssembler::branchEqualTypeIfNeeded(MIRType type, MDefinition* maybeDef, Register tag,
                                         Label* label)
 {
     if (!maybeDef || maybeDef->mightBeType(type)) {
         switch (type) {
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -547,17 +547,17 @@ GetIntrinsicValue(JSContext* cx, HandleP
 
 bool
 CreateThis(JSContext* cx, HandleObject callee, MutableHandleValue rval)
 {
     rval.set(MagicValue(JS_IS_CONSTRUCTING));
 
     if (callee->is<JSFunction>()) {
         JSFunction* fun = &callee->as<JSFunction>();
-        if (fun->isInterpretedConstructor()) {
+        if (fun->isInterpreted() && fun->isConstructor()) {
             JSScript* script = fun->getOrCreateScript(cx);
             if (!script || !script->ensureHasTypes(cx))
                 return false;
             JSObject* thisObj = CreateThisForFunction(cx, callee, GenericObject);
             if (!thisObj)
                 return false;
             rval.set(ObjectValue(*thisObj));
         }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3415,17 +3415,17 @@ JS_IsNativeFunction(JSObject* funobj, JS
         return false;
     JSFunction* fun = &funobj->as<JSFunction>();
     return fun->isNative() && fun->native() == call;
 }
 
 extern JS_PUBLIC_API(bool)
 JS_IsConstructor(JSFunction* fun)
 {
-    return fun->isNativeConstructor() || fun->isInterpretedConstructor();
+    return fun->isConstructor();
 }
 
 JS_PUBLIC_API(JSObject*)
 JS_BindCallable(JSContext* cx, HandleObject target, HandleObject newThis)
 {
     RootedValue thisArg(cx, ObjectValue(*newThis));
     return fun_bind(cx, target, thisArg, nullptr, 0);
 }
@@ -4056,17 +4056,17 @@ CompileFunction(JSContext* cx, const Rea
 
     AutoNameVector formals(cx);
     for (unsigned i = 0; i < nargs; i++) {
         RootedAtom argAtom(cx, Atomize(cx, argnames[i], strlen(argnames[i])));
         if (!argAtom || !formals.append(argAtom->asPropertyName()))
             return false;
     }
 
-    fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED, funAtom,
+    fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom,
                                 gc::AllocKind::FUNCTION, TenuredObject,
                                 enclosingDynamicScope));
     if (!fun)
         return false;
 
     // Make sure to handle cases when we have a polluted scopechain.
     CompileOptions options(cx, optionsArg);
     if (!enclosingDynamicScope->is<GlobalObject>())
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -2326,15 +2326,15 @@ js::ReportIncompatible(JSContext* cx, Ca
 namespace JS {
 namespace detail {
 
 JS_PUBLIC_API(void)
 CheckIsValidConstructible(Value calleev)
 {
     JSObject* callee = &calleev.toObject();
     if (callee->is<JSFunction>())
-        MOZ_ASSERT(callee->as<JSFunction>().isNativeConstructor());
+        MOZ_ASSERT(callee->as<JSFunction>().isConstructor());
     else
         MOZ_ASSERT(callee->constructHook() != nullptr);
 }
 
 } // namespace detail
 } // namespace JS
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -35,57 +35,58 @@ class JSFunction : public js::NativeObje
         Getter,
         Setter,
         AsmJS,                      /* function is an asm.js module or exported function */
         FunctionKindLimit
     };
 
     enum Flags {
         INTERPRETED      = 0x0001,  /* function has a JSScript and environment. */
-        NATIVE_CTOR      = 0x0002,  /* native that can be called as a constructor */
+        CONSTRUCTOR      = 0x0002,  /* function that can be called as a constructor */
         EXTENDED         = 0x0004,  /* structure is FunctionExtended */
         IS_FUN_PROTO     = 0x0008,  /* function is Function.prototype for some global object */
         EXPR_BODY        = 0x0010,  /* arrow function with expression body or
                                      * expression closure: function(x) x*x */
         HAS_GUESSED_ATOM = 0x0020,  /* function had no explicit name, but a
                                        name was guessed for it anyway */
         LAMBDA           = 0x0040,  /* function comes from a FunctionExpression, ArrowFunction, or
                                        Function() call (not a FunctionDeclaration or nonstandard
                                        function-statement) */
         SELF_HOSTED      = 0x0080,  /* function is self-hosted builtin and must not be
                                        decompilable nor constructible. */
-        SELF_HOSTED_CTOR = 0x0100,  /* function is self-hosted builtin constructor and
-                                       must be constructible but not decompilable. */
+        // Free bit
         HAS_REST         = 0x0200,  /* function has a rest (...) parameter */
         INTERPRETED_LAZY = 0x0400,  /* function is interpreted but doesn't have a script yet */
         RESOLVED_LENGTH  = 0x0800,  /* f.length has been resolved (see fun_resolve). */
         RESOLVED_NAME    = 0x1000,  /* f.name has been resolved (see fun_resolve). */
 
         FUNCTION_KIND_SHIFT = 13,
         FUNCTION_KIND_MASK  = 0x7 << FUNCTION_KIND_SHIFT,
 
         ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT,
         ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT,
         METHOD_KIND = Method << FUNCTION_KIND_SHIFT,
         GETTER_KIND = Getter << FUNCTION_KIND_SHIFT,
         SETTER_KIND = Setter << FUNCTION_KIND_SHIFT,
 
         /* Derived Flags values for convenience: */
         NATIVE_FUN = 0,
+        NATIVE_CTOR = NATIVE_FUN | CONSTRUCTOR,
         ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR,
         ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA,
         INTERPRETED_METHOD = INTERPRETED | METHOD_KIND,
-        INTERPRETED_CLASS_CONSTRUCTOR = INTERPRETED | METHOD_KIND,
+        INTERPRETED_CLASS_CONSTRUCTOR = INTERPRETED | METHOD_KIND | CONSTRUCTOR,
         INTERPRETED_GETTER = INTERPRETED | GETTER_KIND,
         INTERPRETED_SETTER = INTERPRETED | SETTER_KIND,
-        INTERPRETED_LAMBDA = INTERPRETED | LAMBDA,
+        INTERPRETED_LAMBDA = INTERPRETED | LAMBDA | CONSTRUCTOR,
         INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND,
-        STABLE_ACROSS_CLONES = NATIVE_CTOR | IS_FUN_PROTO | EXPR_BODY | HAS_GUESSED_ATOM |
-                               LAMBDA | SELF_HOSTED | SELF_HOSTED_CTOR | HAS_REST |
-                               FUNCTION_KIND_MASK
+        INTERPRETED_NORMAL = INTERPRETED | CONSTRUCTOR,
+
+        STABLE_ACROSS_CLONES = IS_FUN_PROTO | CONSTRUCTOR | EXPR_BODY | HAS_GUESSED_ATOM |
+                               LAMBDA | SELF_HOSTED |  HAS_REST | FUNCTION_KIND_MASK
     };
 
     static_assert((INTERPRETED | INTERPRETED_LAZY) == js::JS_FUNCTION_INTERPRETED_BITS,
                   "jsfriendapi.h's JSFunction::INTERPRETED-alike is wrong");
     static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <= FUNCTION_KIND_MASK,
                   "FunctionKind doesn't fit into flags_");
 
   private:
@@ -141,63 +142,58 @@ class JSFunction : public js::NativeObje
     FunctionKind kind() const {
         return static_cast<FunctionKind>((flags_ & FUNCTION_KIND_MASK) >> FUNCTION_KIND_SHIFT);
     }
 
     /* A function can be classified as either native (C++) or interpreted (JS): */
     bool isInterpreted()            const { return flags() & (INTERPRETED | INTERPRETED_LAZY); }
     bool isNative()                 const { return !isInterpreted(); }
 
+    bool isConstructor()            const { return flags() & CONSTRUCTOR; }
+
     /* Possible attributes of a native function: */
-    bool isNativeConstructor()      const { return flags() & NATIVE_CTOR; }
     bool isAsmJSNative()            const { return kind() == AsmJS; }
 
     /* Possible attributes of an interpreted function: */
     bool isFunctionPrototype()      const { return flags() & IS_FUN_PROTO; }
     bool isExprBody()               const { return flags() & EXPR_BODY; }
     bool hasGuessedAtom()           const { return flags() & HAS_GUESSED_ATOM; }
     bool isLambda()                 const { return flags() & LAMBDA; }
     bool isSelfHostedBuiltin()      const { return flags() & SELF_HOSTED; }
-    bool isSelfHostedConstructor()  const { return flags() & SELF_HOSTED_CTOR; }
     bool hasRest()                  const { return flags() & HAS_REST; }
     bool isInterpretedLazy()        const { return flags() & INTERPRETED_LAZY; }
     bool hasScript()                const { return flags() & INTERPRETED; }
 
     // Arrow functions store their lexical |this| in the first extended slot.
     bool isArrow()                  const { return kind() == Arrow; }
     // Every class-constructor is also a method.
     bool isMethod()                 const { return kind() == Method; }
 
     bool isGetter()                 const { return kind() == Getter; }
     bool isSetter()                 const { return kind() == Setter; }
 
     bool isClassConstructor() const {
-        return kind() == Method && isInterpretedConstructor();
+        return kind() == Method && isConstructor();
     }
 
     bool hasResolvedLength()        const { return flags() & RESOLVED_LENGTH; }
     bool hasResolvedName()          const { return flags() & RESOLVED_NAME; }
 
     bool hasJITCode() const {
         if (!hasScript())
             return false;
 
         return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript();
     }
 
     /* Compound attributes: */
     bool isBuiltin() const {
         return (isNative() && !isAsmJSNative()) || isSelfHostedBuiltin();
     }
-    bool isInterpretedConstructor() const {
-        // Note: the JITs inline this check, so be careful when making changes
-        // here. See MacroAssembler::branchIfNotInterpretedConstructor.
-        return isInterpreted() && !isFunctionPrototype() && !isArrow() &&
-               (!isSelfHostedBuiltin() || isSelfHostedConstructor());
-    }
+
     bool isNamedLambda() const {
         return isLambda() && displayAtom() && !hasGuessedAtom();
     }
 
     bool isBuiltinFunctionConstructor();
 
     /* Returns the strictness of this function, which must be interpreted. */
     bool strict() const {
@@ -208,34 +204,38 @@ class JSFunction : public js::NativeObje
     void setFlags(uint16_t flags) {
         this->flags_ = flags;
     }
     void setKind(FunctionKind kind) {
         this->flags_ &= ~FUNCTION_KIND_MASK;
         this->flags_ |= static_cast<uint16_t>(kind) << FUNCTION_KIND_SHIFT;
     }
 
+    // Make the function constructible.
+    void setIsConstructor() {
+        MOZ_ASSERT(!isConstructor());
+        MOZ_ASSERT(isSelfHostedBuiltin());
+        flags_ |= CONSTRUCTOR;
+    }
+
     // Can be called multiple times by the parser.
     void setArgCount(uint16_t nargs) {
         this->nargs_ = nargs;
     }
 
     // Can be called multiple times by the parser.
     void setHasRest() {
         flags_ |= HAS_REST;
     }
 
     void setIsSelfHostedBuiltin() {
         MOZ_ASSERT(!isSelfHostedBuiltin());
         flags_ |= SELF_HOSTED;
-    }
-
-    void setIsSelfHostedConstructor() {
-        MOZ_ASSERT(!isSelfHostedConstructor());
-        flags_ |= SELF_HOSTED_CTOR;
+        // Self-hosted functions should not be constructable.
+        flags_ &= ~CONSTRUCTOR;
     }
 
     void setIsFunctionPrototype() {
         MOZ_ASSERT(!isFunctionPrototype());
         flags_ |= IS_FUN_PROTO;
     }
 
     // Can be called multiple times by the parser.
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2598,17 +2598,17 @@ JSObject::isCallable() const
     return callHook() != nullptr;
 }
 
 bool
 JSObject::isConstructor() const
 {
     if (is<JSFunction>()) {
         const JSFunction& fun = as<JSFunction>();
-        return fun.isNativeConstructor() || fun.isInterpretedConstructor();
+        return fun.isConstructor();
     }
     return constructHook() != nullptr;
 }
 
 JSNative
 JSObject::callHook() const
 {
     const js::Class* clasp = getClass();
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2093,24 +2093,24 @@ DisassembleScript(JSContext* cx, HandleS
                   bool recursive, Sprinter* sp)
 {
     if (fun) {
         Sprint(sp, "flags:");
         if (fun->isLambda())
             Sprint(sp, " LAMBDA");
         if (fun->isHeavyweight())
             Sprint(sp, " HEAVYWEIGHT");
+        if (fun->isConstructor())
+            Sprint(sp, " CONSTRUCTOR");
         if (fun->isExprBody())
             Sprint(sp, " EXPRESSION_CLOSURE");
         if (fun->isFunctionPrototype())
             Sprint(sp, " Function.prototype");
         if (fun->isSelfHostedBuiltin())
             Sprint(sp, " SELF_HOSTED");
-        if (fun->isSelfHostedConstructor())
-            Sprint(sp, " SELF_HOSTED_CTOR");
         if (fun->isArrow())
             Sprint(sp, " ARROW");
         Sprint(sp, "\n");
     }
 
     if (!Disassemble(cx, script, lines, sp))
         return false;
     SrcNotes(cx, script, sp);
--- a/js/src/tests/ecma_6/Class/methodInstallation.js
+++ b/js/src/tests/ecma_6/Class/methodInstallation.js
@@ -55,45 +55,50 @@ for (let a of [testClass,
     assertEq(aMethDesc.enumerable, true);
     aMethDesc.value();
     assertEq(methodCalled, true);
 
     var aGetDesc = Object.getOwnPropertyDescriptor(a.prototype, \"getter\");
     assertEq(aGetDesc.configurable, true);
     assertEq(aGetDesc.enumerable, true);
     aGetDesc.get();
+    assertThrowsInstanceOf(() => new aGetDesc.get, TypeError);
     assertEq(getterCalled, true);
 
     var aSetDesc = Object.getOwnPropertyDescriptor(a.prototype, \"setter\");
     assertEq(aSetDesc.configurable, true);
     assertEq(aSetDesc.enumerable, true);
     aSetDesc.set();
+    assertThrowsInstanceOf(() => new aSetDesc.set, TypeError);
     assertEq(setterCalled, true);
     assertDeepEq(aSetDesc, Object.getOwnPropertyDescriptor(a.prototype, \"setter\"));
 
     assertEq(Object.getOwnPropertyDescriptor(new a(), \"staticMethod\"), undefined);
     var aStaticMethDesc = Object.getOwnPropertyDescriptor(a, \"staticMethod\");
     assertEq(aStaticMethDesc.configurable, true);
     assertEq(aStaticMethDesc.enumerable, true);
     assertEq(aStaticMethDesc.writable, true);
     aStaticMethDesc.value();
+    assertThrowsInstanceOf(() => new aStaticMethDesc.value, TypeError);
     assertEq(staticMethodCalled, true);
 
     assertEq(Object.getOwnPropertyDescriptor(new a(), \"staticGetter\"), undefined);
     var aStaticGetDesc = Object.getOwnPropertyDescriptor(a, \"staticGetter\");
     assertEq(aStaticGetDesc.configurable, true);
     assertEq(aStaticGetDesc.enumerable, true);
     aStaticGetDesc.get();
+    assertThrowsInstanceOf(() => new aStaticGetDesc.get, TypeError);
     assertEq(staticGetterCalled, true);
 
     assertEq(Object.getOwnPropertyDescriptor(new a(), \"staticSetter\"), undefined);
     var aStaticSetDesc = Object.getOwnPropertyDescriptor(a, \"staticSetter\");
     assertEq(aStaticSetDesc.configurable, true);
     assertEq(aStaticSetDesc.enumerable, true);
     aStaticSetDesc.set();
+    assertThrowsInstanceOf(() => new aStaticSetDesc.set, TypeError);
     assertEq(staticSetterCalled, true);
 
     assertEq([...new a()].join(), "cow,pig");
 }
 `;
 
 if (classesEnabled())
     eval(test);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Object/accessor-non-constructor.js
@@ -0,0 +1,20 @@
+var obj = { get a() { return 1; } };
+assertThrowsInstanceOf(() => {
+    new Object.getOwnPropertyDescriptor(obj, "a").get
+}, TypeError);
+
+obj = { set a(b) { } };
+assertThrowsInstanceOf(() => {
+    new Object.getOwnPropertyDescriptor(obj, "a").set
+}, TypeError);
+
+obj = { get a() { return 1; }, set a(b) { } };
+assertThrowsInstanceOf(() => {
+    new Object.getOwnPropertyDescriptor(obj, "a").get
+}, TypeError);
+assertThrowsInstanceOf(() => {
+    new Object.getOwnPropertyDescriptor(obj, "a").set
+}, TypeError);
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Object/method-non-constructor.js
@@ -0,0 +1,12 @@
+var obj = { method() { } };
+assertThrowsInstanceOf(() => {
+    new obj.method;
+}, TypeError);
+
+obj = { constructor() { } };
+assertThrowsInstanceOf(() => {
+    new obj.constructor;
+}, TypeError);
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
--- a/js/src/tests/ecma_6/TypedArray/of.js
+++ b/js/src/tests/ecma_6/TypedArray/of.js
@@ -55,19 +55,23 @@ for (var constructor of constructors) {
     var invalidConstructors = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
                                constructor.of, () => {}];
     invalidConstructors.forEach(C => {
         assertThrowsInstanceOf(() => {
             constructor.of.call(C);
         }, TypeError);
     });
 
-    // FIXME: Should throw if `this` is a method definition or a getter/setter function, see bug 1059908.
-    constructor.of.call({method() {}}.method);
-    constructor.of.call(Object.getOwnPropertyDescriptor({get getter() {}}, "getter").get);
+    // Throw if `this` is a method definition or a getter/setter function.
+    assertThrowsInstanceOf(() => {
+        constructor.of.call({method() {}}.method);
+    }, TypeError);
+    assertThrowsInstanceOf(() => {
+        constructor.of.call(Object.getOwnPropertyDescriptor({get getter() {}}, "getter").get);
+    }, TypeError);
 
     // Generators are also legal constructors.
     assertEq(constructor.of.call(function*(len) {
         return len;
     }, "a", "b", "c").next().value, 3);
 
     // An exception might be thrown in a strict assignment to the new object's indexed properties.
     assertThrowsInstanceOf(() => {
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -717,19 +717,20 @@ js::Invoke(JSContext* cx, CallArgs args,
         JSNative call = args.callee().callHook();
         if (!call)
             return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, construct);
         return CallJSNative(cx, call, args);
     }
 
     /* Invoke native functions. */
     JSFunction* fun = &args.callee().as<JSFunction>();
-    MOZ_ASSERT_IF(construct, !fun->isNativeConstructor());
-    if (fun->isNative())
+    if (fun->isNative()) {
+        MOZ_ASSERT_IF(construct, !fun->isConstructor());
         return CallJSNative(cx, fun->native(), args);
+    }
 
     if (!fun->getOrCreateScript(cx))
         return false;
 
     /* Run function until JSOP_RETRVAL, JSOP_RETURN or error. */
     InvokeState state(cx, args, initial);
 
     // Check to see if createSingleton flag should be set for this frame.
@@ -796,22 +797,22 @@ js::InvokeConstructor(JSContext* cx, Cal
 
     if (!args.calleev().isObject())
         return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT);
 
     JSObject& callee = args.callee();
     if (callee.is<JSFunction>()) {
         RootedFunction fun(cx, &callee.as<JSFunction>());
 
-        if (fun->isNativeConstructor())
+        if (!fun->isConstructor())
+            return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT);
+
+        if (fun->isNative())
             return CallJSNativeConstructor(cx, fun->native(), args);
 
-        if (!fun->isInterpretedConstructor())
-            return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT);
-
         if (!Invoke(cx, args, CONSTRUCT))
             return false;
 
         MOZ_ASSERT(args.rval().isObject());
         return true;
     }
 
     JSNative construct = callee.constructHook();
@@ -2942,17 +2943,17 @@ CASE(JSOP_FUNCALL)
     CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
 
     bool construct = (*REGS.pc == JSOP_NEW);
 
     RootedFunction& fun = rootFunction0;
     bool isFunction = IsFunctionObject(args.calleev(), fun.address());
 
     /* Don't bother trying to fast-path calls to scripted non-constructors. */
-    if (!isFunction || !fun->isInterpretedConstructor()) {
+    if (!isFunction || !fun->isInterpreted() || !fun->isConstructor()) {
         if (construct) {
             if (!InvokeConstructor(cx, args))
                 goto error;
         } else {
             if (!Invoke(cx, args))
                 goto error;
         }
         Value* newsp = args.spAfterCall();
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -235,29 +235,30 @@ intrinsic_AssertionFailed(JSContext* cx,
 
 static bool
 intrinsic_MakeConstructible(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 2);
     MOZ_ASSERT(args[0].isObject());
     MOZ_ASSERT(args[0].toObject().is<JSFunction>());
+    MOZ_ASSERT(args[0].toObject().as<JSFunction>().isSelfHostedBuiltin());
     MOZ_ASSERT(args[1].isObject());
 
     // Normal .prototype properties aren't enumerable.  But for this to clone
     // correctly, it must be enumerable.
     RootedObject ctor(cx, &args[0].toObject());
     if (!DefineProperty(cx, ctor, cx->names().prototype, args[1],
                         nullptr, nullptr,
                         JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
     {
         return false;
     }
 
-    ctor->as<JSFunction>().setIsSelfHostedConstructor();
+    ctor->as<JSFunction>().setIsConstructor();
     args.rval().setUndefined();
     return true;
 }
 
 /*
  * Used to decompile values in the nearest non-builtin stack frame, falling
  * back to decompiling in the current frame. Helpful for printing higher-order
  * function arguments.