Commit 8c1a4330 authored by zhengxing.li's avatar zhengxing.li Committed by Commit bot

X87: [runtime] Fix ES6 9.2.1 [[Call]] when encountering a classConstructor.

  port ab840259 (r31790).

  original commit message:
  The current implementation of classes throws the TypeError at the wrong
  point, after activating a new context when directly calling a class
  constructor. According to the spec, the TypeError has to be thrown
  in the caller context.

BUG=

Review URL: https://codereview.chromium.org/1419793007

Cr-Commit-Position: refs/heads/master@{#31815}
parent 7b704c4f
...@@ -1532,19 +1532,32 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm) { ...@@ -1532,19 +1532,32 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm) {
// -- eax : the number of arguments (not including the receiver) // -- eax : the number of arguments (not including the receiver)
// -- edi : the function to call (checked to be a JSFunction) // -- edi : the function to call (checked to be a JSFunction)
// ----------------------------------- // -----------------------------------
// See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
Label convert, convert_global_proxy, convert_to_object, done_convert; Label convert, convert_global_proxy, convert_to_object, done_convert;
__ AssertFunction(edi); __ AssertFunction(edi);
// TODO(bmeurer): Throw a TypeError if function's [[FunctionKind]] internal __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
// slot is "classConstructor".
{
Label non_class_constructor;
// Check whether the current function is a classConstructor.
__ test_b(FieldOperand(edx, SharedFunctionInfo::kFunctionKindByteOffset),
SharedFunctionInfo::kClassConstructorBitsWithinByte);
__ j(zero, &non_class_constructor, Label::kNear);
// Step: 2, If we call a classConstructor Function throw a TypeError.
{
FrameScope frame(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowConstructorNonCallableError, 0);
}
__ bind(&non_class_constructor);
}
// Enter the context of the function; ToObject has to run in the function // Enter the context of the function; ToObject has to run in the function
// context, and we also need to take the global proxy from the function // context, and we also need to take the global proxy from the function
// context in case of conversion. // context in case of conversion.
// See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset == STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
SharedFunctionInfo::kStrictModeByteOffset); SharedFunctionInfo::kStrictModeByteOffset);
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
__ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
// We need to convert the receiver for non-native sloppy mode functions. // We need to convert the receiver for non-native sloppy mode functions.
__ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset), __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset),
(1 << SharedFunctionInfo::kNativeBitWithinByte) | (1 << SharedFunctionInfo::kNativeBitWithinByte) |
......
...@@ -1737,14 +1737,17 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) { ...@@ -1737,14 +1737,17 @@ static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) {
static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) { static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) {
// ----------- S t a t e -------------
// -- edi : the function to call
// -- edx : the function's shared function info
// -----------------------------------
// Do not transform the receiver for strict mode functions. // Do not transform the receiver for strict mode functions.
__ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); __ test_b(FieldOperand(edx, SharedFunctionInfo::kStrictModeByteOffset),
__ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
1 << SharedFunctionInfo::kStrictModeBitWithinByte); 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
__ j(not_equal, cont); __ j(not_equal, cont);
// Do not transform the receiver for natives (shared already in ecx). // Do not transform the receiver for natives (shared already in ecx).
__ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset), __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset),
1 << SharedFunctionInfo::kNativeBitWithinByte); 1 << SharedFunctionInfo::kNativeBitWithinByte);
__ j(not_equal, cont); __ j(not_equal, cont);
} }
...@@ -1769,6 +1772,24 @@ static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) { ...@@ -1769,6 +1772,24 @@ static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
} }
static void EmitClassConstructorCallCheck(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- edi : the function to call
// -- edx : the function's shared function info
// -----------------------------------
// ClassConstructor Check: ES6 section 9.2.1 [[Call]]
Label non_class_constructor;
// Check whether the current function is a classConstructor.
__ test_b(FieldOperand(edx, SharedFunctionInfo::kFunctionKindByteOffset),
SharedFunctionInfo::kClassConstructorBitsWithinByte);
__ j(zero, &non_class_constructor, Label::kNear);
// If we call a classConstructor Function throw a TypeError
// indirectly via the CallFunction builtin.
__ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET);
__ bind(&non_class_constructor);
}
static void CallFunctionNoFeedback(MacroAssembler* masm, static void CallFunctionNoFeedback(MacroAssembler* masm,
int argc, bool needs_checks, int argc, bool needs_checks,
bool call_as_method) { bool call_as_method) {
...@@ -1784,6 +1805,9 @@ static void CallFunctionNoFeedback(MacroAssembler* masm, ...@@ -1784,6 +1805,9 @@ static void CallFunctionNoFeedback(MacroAssembler* masm,
__ j(not_equal, &slow); __ j(not_equal, &slow);
} }
__ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
EmitClassConstructorCallCheck(masm);
// Fast-case: Just invoke the function. // Fast-case: Just invoke the function.
ParameterCount actual(argc); ParameterCount actual(argc);
...@@ -1956,6 +1980,10 @@ void CallICStub::Generate(MacroAssembler* masm) { ...@@ -1956,6 +1980,10 @@ void CallICStub::Generate(MacroAssembler* masm) {
Immediate(Smi::FromInt(CallICNexus::kCallCountIncrement))); Immediate(Smi::FromInt(CallICNexus::kCallCountIncrement)));
__ bind(&have_js_function); __ bind(&have_js_function);
__ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
EmitClassConstructorCallCheck(masm);
if (CallAsMethod()) { if (CallAsMethod()) {
EmitContinueIfStrictOrNative(masm, &cont); EmitContinueIfStrictOrNative(masm, &cont);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment