Skip to content

Commit b8d71ec

Browse files
authored
Fix Object constructor behavior when new target is provided (#6341)
Authored-by: Kevin Smith @zenparsing
1 parent a125635 commit b8d71ec

File tree

2 files changed

+46
-33
lines changed

2 files changed

+46
-33
lines changed

lib/Runtime/Library/JavascriptObject.cpp

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,32 @@ using namespace Js;
99
Var JavascriptObject::NewInstance(RecyclableObject* function, CallInfo callInfo, ...)
1010
{
1111
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
12-
1312
ARGUMENTS(args, callInfo);
1413
ScriptContext* scriptContext = function->GetScriptContext();
14+
JavascriptLibrary* library = scriptContext->GetLibrary();
1515

1616
AssertMsg(args.HasArg(), "Should always have implicit 'this'");
1717

18-
// SkipDefaultNewObject function flag should have prevented the default object from
19-
// being created, except when call true a host dispatch.
2018
Var newTarget = args.GetNewTarget();
21-
bool isCtorSuperCall = JavascriptOperators::GetAndAssertIsConstructorSuperCall(args);
19+
if (JavascriptOperators::GetAndAssertIsConstructorSuperCall(args) &&
20+
newTarget != function)
21+
{
22+
return JavascriptOperators::OrdinaryCreateFromConstructor(
23+
VarTo<RecyclableObject>(newTarget),
24+
library->CreateObject(true),
25+
nullptr,
26+
scriptContext);
27+
}
2228

23-
if (args.Info.Count > 1)
29+
Var arg = args.Info.Count > 1 ? args[1] : library->GetUndefined();
30+
switch (JavascriptOperators::GetTypeId(arg))
2431
{
25-
switch (JavascriptOperators::GetTypeId(args[1]))
26-
{
2732
case TypeIds_Undefined:
2833
case TypeIds_Null:
29-
// Break to return a new object
30-
break;
34+
// Null and undefined result in a new object
35+
return (callInfo.Flags & CallFlags_NotUsed)
36+
? arg
37+
: library->CreateObject(true);
3138

3239
case TypeIds_StringObject:
3340
case TypeIds_Function:
@@ -43,32 +50,14 @@ Var JavascriptObject::NewInstance(RecyclableObject* function, CallInfo callInfo,
4350
case TypeIds_Arguments:
4451
case TypeIds_ActivationObject:
4552
case TypeIds_SymbolObject:
46-
return isCtorSuperCall ?
47-
JavascriptOperators::OrdinaryCreateFromConstructor(VarTo<RecyclableObject>(newTarget), VarTo<RecyclableObject>(args[1]), nullptr, scriptContext) :
48-
args[1];
49-
50-
default:
51-
RecyclableObject* result = nullptr;
52-
if (FALSE == JavascriptConversion::ToObject(args[1], scriptContext, &result))
53-
{
54-
// JavascriptConversion::ToObject should only return FALSE for null and undefined.
55-
Assert(false);
56-
}
57-
58-
return isCtorSuperCall ?
59-
JavascriptOperators::OrdinaryCreateFromConstructor(VarTo<RecyclableObject>(newTarget), result, nullptr, scriptContext) :
60-
result;
61-
}
53+
// Since we know this is an object, we can skip ToObject
54+
return arg;
6255
}
6356

64-
if (callInfo.Flags & CallFlags_NotUsed)
65-
{
66-
return args[0];
67-
}
68-
Var newObj = scriptContext->GetLibrary()->CreateObject(true);
69-
return isCtorSuperCall ?
70-
JavascriptOperators::OrdinaryCreateFromConstructor(VarTo<RecyclableObject>(newTarget), VarTo<RecyclableObject>(newObj), nullptr, scriptContext) :
71-
newObj;
57+
RecyclableObject* result = nullptr;
58+
JavascriptConversion::ToObject(arg, scriptContext, &result);
59+
Assert(result);
60+
return result;
7261
}
7362

7463
Var JavascriptObject::EntryHasOwnProperty(RecyclableObject* function, CallInfo callInfo, ...)

test/es6/reflectConstructConsumeNewTarget.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,30 @@ var tests = [
4141

4242
assert.throws(function () { Reflect.construct(myDerivedClass, [], undefined ) }, TypeError, "undefined is not a constructor", "'newTarget' is not a constructor");
4343
}
44+
},
45+
{
46+
name: "Reflect.construct should work with Object constructor",
47+
body: function () {
48+
var p = {};
49+
var a = { __proto__: p };
50+
51+
new class extends Object {
52+
constructor() {
53+
super(a);
54+
assert.isTrue(a.__proto__ === p);
55+
}
56+
};
57+
58+
Reflect.construct(Object, [a]);
59+
assert.isTrue(a.__proto__ === p);
60+
61+
var q = {};
62+
function C() {}
63+
C.prototype = q;
64+
var obj = Reflect.construct(Object, [a], C);
65+
assert.isTrue(obj.__proto__ === q);
66+
assert.isTrue(a.__proto__ === p);
67+
}
4468
}
4569
];
4670

0 commit comments

Comments
 (0)