Commit 46253e74 authored by littledan's avatar littledan Committed by Commit bot

[esnext] Fix various callsites to use is_resumable, not is_generator

Async functions are built out of generators, but the
SharedFunctionInfo returns false for is_generator. is_resumable is
the broader query. This patch fixes many parts of V8 to refer
to is_resumable as appropriate.

One incidental change is to remove a check for generators extending
classes. This is part of a general check for constructors being the
only thing which can extend classes, so it is removed here and the
error message for the general case is made more accurate.

BUG=v8:4483

Review-Url: https://codereview.chromium.org/1996943002
Cr-Commit-Position: refs/heads/master@{#36621}
parent 0ac67d74
......@@ -874,10 +874,11 @@ MaybeHandle<Code> GetBaselineCode(Handle<JSFunction> function) {
return MaybeHandle<Code>();
}
// TODO(4280): For now we do not switch generators to baseline code because
// there might be suspended activations stored in generator objects on the
// heap. We could eventually go directly to TurboFan in this case.
if (function->shared()->is_generator()) {
// TODO(4280): For now we do not switch generators or async functions to
// baseline code because there might be suspended activations stored in
// generator objects on the heap. We could eventually go directly to
// TurboFan in this case.
if (function->shared()->is_resumable()) {
return MaybeHandle<Code>();
}
......@@ -1308,10 +1309,11 @@ bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) {
CompilationInfo unoptimized(info->parse_info(), info->closure());
unoptimized.EnableDeoptimizationSupport();
// TODO(4280): For now we do not switch generators to baseline code because
// there might be suspended activations stored in generator objects on the
// heap. We could eventually go directly to TurboFan in this case.
if (shared->is_generator()) return false;
// TODO(4280): For now we do not switch generators or async functions to
// baseline code because there might be suspended activations stored in
// generator objects on the heap. We could eventually go directly to
// TurboFan in this case.
if (shared->is_resumable()) return false;
// TODO(4280): For now we disable switching to baseline code in the presence
// of interpreter activations of the given function. The reasons are:
......
......@@ -1325,7 +1325,7 @@ bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) {
// smarter here and avoid the heap walk.
HeapIterator iterator(isolate_->heap());
HeapObject* obj;
bool include_generators = !is_interpreted && shared->is_generator();
bool find_resumables = !is_interpreted && shared->is_resumable();
while ((obj = iterator.next())) {
if (obj->IsJSFunction()) {
......@@ -1336,7 +1336,9 @@ bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) {
}
if (is_interpreted) continue;
if (function->shared() == *shared) functions.Add(handle(function));
} else if (include_generators && obj->IsJSGeneratorObject()) {
} else if (find_resumables && obj->IsJSGeneratorObject()) {
// This case handles async functions as well, as they use generator
// objects for in-progress async function execution.
JSGeneratorObject* generator_obj = JSGeneratorObject::cast(obj);
if (!generator_obj->is_suspended()) continue;
JSFunction* function = generator_obj->function();
......
......@@ -1680,7 +1680,7 @@ static const char* DropActivationsInActiveThreadImpl(Isolate* isolate,
if (frame->is_java_script()) {
SharedFunctionInfo* shared =
JavaScriptFrame::cast(frame)->function()->shared();
if (shared->is_generator()) {
if (shared->is_resumable()) {
non_droppable_frame_found = true;
non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR;
break;
......
......@@ -1298,7 +1298,10 @@ Handle<JSFunction> Factory::NewFunction(Handle<String> name, Handle<Code> code,
ElementsKind elements_kind =
type == JS_ARRAY_TYPE ? FAST_SMI_ELEMENTS : FAST_HOLEY_SMI_ELEMENTS;
Handle<Map> initial_map = NewMap(type, instance_size, elements_kind);
if (!function->shared()->is_generator()) {
// TODO(littledan): Why do we have this is_generator test when
// NewFunctionPrototype already handles finding an appropriately
// shared prototype?
if (!function->shared()->is_resumable()) {
if (prototype->IsTheHole()) {
prototype = NewFunctionPrototype(function);
} else if (install_constructor) {
......@@ -1327,11 +1330,12 @@ Handle<JSObject> Factory::NewFunctionPrototype(Handle<JSFunction> function) {
// can be from a different context.
Handle<Context> native_context(function->context()->native_context());
Handle<Map> new_map;
if (function->shared()->is_generator()) {
// Generator prototypes can share maps since they don't have "constructor"
// properties.
if (function->shared()->is_resumable()) {
// Generator and async function prototypes can share maps since they
// don't have "constructor" properties.
new_map = handle(native_context->generator_object_prototype_map());
} else {
CHECK(!function->shared()->is_async());
// Each function prototype gets a fresh map to avoid unwanted sharing of
// maps between prototypes of different constructors.
Handle<JSFunction> object_function(native_context->object_function());
......@@ -1342,7 +1346,7 @@ Handle<JSObject> Factory::NewFunctionPrototype(Handle<JSFunction> function) {
DCHECK(!new_map->is_prototype_map());
Handle<JSObject> prototype = NewJSObjectFromMap(new_map);
if (!function->shared()->is_generator()) {
if (!function->shared()->is_resumable()) {
JSObject::AddProperty(prototype, constructor_string(), function, DONT_ENUM);
}
......
......@@ -121,10 +121,8 @@ class CallSite {
T(DefineDisallowed, "Cannot define property:%, object is not extensible.") \
T(DetachedOperation, "Cannot perform % on a detached ArrayBuffer") \
T(DuplicateTemplateProperty, "Object template has duplicate property '%'") \
T(ExtendsValueGenerator, \
"Class extends value % may not be a generator function") \
T(ExtendsValueNotFunction, \
"Class extends value % is not a function or null") \
T(ExtendsValueNotConstructor, \
"Class extends value % is not a constructor or null") \
T(FirstArgumentNotRegExp, \
"First argument to % must not be a regular expression") \
T(FunctionBind, "Bind must be called on a function") \
......
......@@ -876,6 +876,8 @@ void JSFunction::JSFunctionPrint(std::ostream& os) { // NOLINT
<< shared()->internal_formal_parameter_count();
if (shared()->is_generator()) {
os << "\n - generator";
} else if (shared()->is_async()) {
os << "\n - async";
}
os << "\n - context = " << Brief(context());
os << "\n - literals = " << Brief(literals());
......
......@@ -94,13 +94,8 @@ static MaybeHandle<Object> DefineClass(Isolate* isolate,
if (super_class->IsNull()) {
prototype_parent = isolate->factory()->null_value();
} else if (super_class->IsConstructor()) {
if (super_class->IsJSFunction() &&
Handle<JSFunction>::cast(super_class)->shared()->is_generator()) {
THROW_NEW_ERROR(
isolate,
NewTypeError(MessageTemplate::kExtendsValueGenerator, super_class),
Object);
}
DCHECK(!super_class->IsJSFunction() ||
!Handle<JSFunction>::cast(super_class)->shared()->is_resumable());
ASSIGN_RETURN_ON_EXCEPTION(
isolate, prototype_parent,
Runtime::GetObjectProperty(isolate, super_class,
......@@ -114,10 +109,10 @@ static MaybeHandle<Object> DefineClass(Isolate* isolate,
}
constructor_parent = super_class;
} else {
THROW_NEW_ERROR(
isolate,
NewTypeError(MessageTemplate::kExtendsValueNotFunction, super_class),
Object);
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kExtendsValueNotConstructor,
super_class),
Object);
}
}
......
......@@ -91,7 +91,7 @@ bytecodes: [
B(TestEqualStrict), R(12),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), U16(129),
B(Wide), B(LdaSmi), U16(128),
B(Star), R(12),
B(LdaConstant), U8(8),
B(Star), R(13),
......@@ -236,7 +236,7 @@ bytecodes: [
B(TestEqualStrict), R(13),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), U16(129),
B(Wide), B(LdaSmi), U16(128),
B(Star), R(13),
B(LdaConstant), U8(8),
B(Star), R(14),
......@@ -393,7 +393,7 @@ bytecodes: [
B(TestEqualStrict), R(12),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), U16(129),
B(Wide), B(LdaSmi), U16(128),
B(Star), R(12),
B(LdaConstant), U8(8),
B(Star), R(13),
......@@ -540,7 +540,7 @@ bytecodes: [
B(TestEqualStrict), R(11),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), U16(129),
B(Wide), B(LdaSmi), U16(128),
B(Star), R(11),
B(LdaConstant), U8(10),
B(Star), R(12),
......
......@@ -480,7 +480,7 @@ bytecodes: [
B(TestEqualStrict), R(10),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), U16(129),
B(Wide), B(LdaSmi), U16(128),
B(Star), R(10),
B(LdaConstant), U8(14),
B(Star), R(11),
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-debug-as debug
var Debug = debug.Debug;
var break_count = 0;
var exception = null;
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Break) return;
try {
break_count++;
var line = exec_state.frame(0).sourceLineText();
print(line);
assertTrue(line.indexOf(`B${break_count}`) > 0);
} catch (e) {
exception = e;
}
}
function* g() {
setbreaks();
yield 1; // B1
}
function* f() {
yield* g();
return 2; // B2
}
function setbreaks() {
Debug.setListener(listener);
Debug.setBreakPoint(g, 2);
Debug.setBreakPoint(f, 2);
}
for (let _ of f()) { }
assertEquals(2, break_count);
assertNull(exception);
Debug.setListener(null);
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-debug-as debug
var Debug = debug.Debug;
var break_count = 0;
var exception = null;
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Break) return;
try {
break_count++;
var line = exec_state.frame(0).sourceLineText();
assertTrue(line.indexOf(`B${break_count}`) > 0);
} catch (e) {
exception = e;
}
}
Debug.setListener(listener);
function* g() {
yield 1;
}
function* f() {
yield* g(); // B1
assertEquals(2, break_count); // B2
return 1; // B3
}
Debug.setBreakPoint(f, 1);
Debug.setBreakPoint(f, 2);
Debug.setBreakPoint(f, 3);
for (let _ of f()) { }
assertEquals(3, break_count);
assertNull(exception);
Debug.setListener(null);
......@@ -345,3 +345,6 @@ assertEquals("async x => { return x }", (async x => { return x }).toString());
class AsyncMethod { async foo() { } }
assertEquals("async foo() { }", Function.prototype.toString.call(AsyncMethod.prototype.foo));
assertEquals("async foo() { }", Function.prototype.toString.call({async foo() { }}.foo));
// Async functions are not constructible
assertThrows(() => class extends (async function() {}) {}, TypeError);
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-debug-as debug
// Flags: --harmony-async-await --allow-natives-syntax
var Debug = debug.Debug;
function assertEqualsAsync(expected, run, msg) {
var actual;
var hadValue = false;
var hadError = false;
var promise = run();
if (typeof promise !== "object" || typeof promise.then !== "function") {
throw new MjsUnitAssertionError(
"Expected " + run.toString() +
" to return a Promise, but it returned " + promise);
}
promise.then(function(value) { hadValue = true; actual = value; },
function(error) { hadError = true; actual = error; });
assertFalse(hadValue || hadError);
%RunMicrotasks();
if (hadError) throw actual;
assertTrue(
hadValue, "Expected '" + run.toString() + "' to produce a value");
assertEquals(expected, actual, msg);
}
var break_count = 0;
var exception = null;
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Break) return;
try {
break_count++;
var line = exec_state.frame(0).sourceLineText();
print(line);
assertTrue(line.indexOf(`B${break_count}`) > 0);
} catch (e) {
exception = e;
}
}
async function g() {
setbreaks();
throw 1; // B1
}
async function f() {
try {
await g();
} catch (e) {}
return 2; // B2
}
function setbreaks() {
Debug.setListener(listener);
Debug.setBreakPoint(g, 2);
Debug.setBreakPoint(f, 4);
}
f();
%RunMicrotasks();
assertEqualsAsync(2, async () => break_count);
assertEqualsAsync(null, async () => exception);
Debug.setListener(null);
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-debug-as debug
// Flags: --harmony-async-await --allow-natives-syntax
var Debug = debug.Debug;
function assertEqualsAsync(expected, run, msg) {
var actual;
var hadValue = false;
var hadError = false;
var promise = run();
if (typeof promise !== "object" || typeof promise.then !== "function") {
throw new MjsUnitAssertionError(
"Expected " + run.toString() +
" to return a Promise, but it returned " + promise);
}
promise.then(function(value) { hadValue = true; actual = value; },
function(error) { hadError = true; actual = error; });
assertFalse(hadValue || hadError);
%RunMicrotasks();
if (hadError) throw actual;
assertTrue(
hadValue, "Expected '" + run.toString() + "' to produce a value");
assertEquals(expected, actual, msg);
}
var break_count = 0;
var exception = null;
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Break) return;
try {
break_count++;
var line = exec_state.frame(0).sourceLineText();
assertTrue(line.indexOf(`B${break_count}`) > 0);
} catch (e) {
exception = e;
}
}
Debug.setListener(listener);
async function g() {
throw 1;
}
async function f() {
try {
await g(); // B1
} catch (e) {}
assertEquals(2, break_count); // B2
return 1; // B3
}
Debug.setBreakPoint(f, 2);
Debug.setBreakPoint(f, 4);
Debug.setBreakPoint(f, 5);
f();
%RunMicrotasks();
assertEqualsAsync(3, async () => break_count);
assertEqualsAsync(null, async () => exception);
Debug.setListener(null);
......@@ -23,8 +23,8 @@ PASS x.prototype.__proto__ is Base.prototype
PASS Object.getPrototypeOf(x.prototype) is Base.prototype
PASS x = class extends null { constructor() { } }; x.__proto__ is Function.prototype
PASS x.__proto__ is Function.prototype
PASS x = class extends 3 { constructor() { } }; x.__proto__ threw exception TypeError: Class extends value 3 is not a function or null.
PASS x = class extends "abc" { constructor() { } }; x.__proto__ threw exception TypeError: Class extends value abc is not a function or null.
PASS x = class extends 3 { constructor() { } }; x.__proto__ threw exception TypeError: Class extends value 3 is not a constructor or null.
PASS x = class extends "abc" { constructor() { } }; x.__proto__ threw exception TypeError: Class extends value abc is not a constructor or null.
PASS baseWithBadPrototype = function () {}; baseWithBadPrototype.prototype = 3; new baseWithBadPrototype did not throw exception.
PASS x = class extends baseWithBadPrototype { constructor() { } } threw exception TypeError: Class extends value does not have valid prototype property 3.
PASS baseWithBadPrototype.prototype = "abc" did not throw exception.
......@@ -32,8 +32,8 @@ PASS x = class extends baseWithBadPrototype { constructor() { } } threw exceptio
PASS baseWithBadPrototype.prototype = null; x = class extends baseWithBadPrototype { constructor() { } } did not throw exception.
PASS x = 1; c = class extends ++x { constructor() { } }; threw exception SyntaxError: Unexpected token ++.
PASS x = 1; c = class extends x++ { constructor() { } }; threw exception SyntaxError: Unexpected token ++.
PASS x = 1; c = class extends (++x) { constructor() { } }; threw exception TypeError: Class extends value 2 is not a function or null.
PASS x = 1; c = class extends (x++) { constructor() { } }; threw exception TypeError: Class extends value 1 is not a function or null.
PASS x = 1; c = class extends (++x) { constructor() { } }; threw exception TypeError: Class extends value 2 is not a constructor or null.
PASS x = 1; c = class extends (x++) { constructor() { } }; threw exception TypeError: Class extends value 1 is not a constructor or null.
PASS x = 1; try { c = class extends (++x) { constructor() { } } } catch (e) { }; x is 2
PASS x = 1; try { c = class extends (x++) { constructor() { } } } catch (e) { }; x is 2
PASS namespace = {}; namespace.A = class { }; namespace.B = class extends namespace.A { } did not throw exception.
......@@ -47,17 +47,17 @@ PASS namespace = {}; namespace.A = class { constructor() { } }; function getClas
PASS namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends (false||null||namespace.A) { constructor() { } } did not throw exception.
PASS namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends false||null||namespace.A { constructor() { } } threw exception SyntaxError: Unexpected token ||.
PASS x = 1; namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends (x++, namespace.A) { constructor() { } }; did not throw exception.
PASS x = 1; namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends (namespace.A, x++) { constructor() { } }; threw exception TypeError: Class extends value 1 is not a function or null.
PASS namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends new namespace.A { constructor() { } } threw exception TypeError: Class extends value [object Object] is not a function or null.
PASS namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends new namespace.A() { constructor() { } } threw exception TypeError: Class extends value [object Object] is not a function or null.
PASS x = 1; namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends (namespace.A, x++) { constructor() { } }; threw exception TypeError: Class extends value 1 is not a constructor or null.
PASS namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends new namespace.A { constructor() { } } threw exception TypeError: Class extends value [object Object] is not a constructor or null.
PASS namespace = {}; namespace.A = class { constructor() { } }; namespace.B = class extends new namespace.A() { constructor() { } } threw exception TypeError: Class extends value [object Object] is not a constructor or null.
PASS x = 1; namespace = {}; namespace.A = class { constructor() { } }; try { namespace.B = class extends (x++, namespace.A) { constructor() { } } } catch (e) { } x is 2
PASS x = 1; namespace = {}; namespace.A = class { constructor() { } }; try { namespace.B = class extends (namespace.A, x++) { constructor() { } } } catch (e) { } x is 2
PASS Object.getPrototypeOf((class { constructor () { } }).prototype) is Object.prototype
PASS Object.getPrototypeOf((class extends null { constructor () { super(); } }).prototype) is null
PASS new (class extends undefined { constructor () { this } }) threw exception TypeError: Class extends value undefined is not a function or null.
PASS new (class extends undefined { constructor () { super(); } }) threw exception TypeError: Class extends value undefined is not a function or null.
PASS x = {}; new (class extends undefined { constructor () { return x; } }) threw exception TypeError: Class extends value undefined is not a function or null.
PASS y = 12; new (class extends undefined { constructor () { return y; } }) threw exception TypeError: Class extends value undefined is not a function or null.
PASS new (class extends undefined { constructor () { this } }) threw exception TypeError: Class extends value undefined is not a constructor or null.
PASS new (class extends undefined { constructor () { super(); } }) threw exception TypeError: Class extends value undefined is not a constructor or null.
PASS x = {}; new (class extends undefined { constructor () { return x; } }) threw exception TypeError: Class extends value undefined is not a constructor or null.
PASS y = 12; new (class extends undefined { constructor () { return y; } }) threw exception TypeError: Class extends value undefined is not a constructor or null.
PASS class x {}; new (class extends null { constructor () { return new x; } }) instanceof x is true
PASS new (class extends null { constructor () { this; } }) threw exception ReferenceError: this is not defined.
PASS new (class extends null { constructor () { super(); } }) threw exception TypeError: super is not a constructor.
......
......@@ -58,8 +58,8 @@ shouldBe('x.prototype.__proto__', 'Base.prototype');
shouldBe('Object.getPrototypeOf(x.prototype)', 'Base.prototype');
shouldBe('x = class extends null { constructor() { } }; x.__proto__', 'Function.prototype');
shouldBe('x.__proto__', 'Function.prototype');
shouldThrow('x = class extends 3 { constructor() { } }; x.__proto__', '"TypeError: Class extends value 3 is not a function or null"');
shouldThrow('x = class extends "abc" { constructor() { } }; x.__proto__', '"TypeError: Class extends value abc is not a function or null"');
shouldThrow('x = class extends 3 { constructor() { } }; x.__proto__', '"TypeError: Class extends value 3 is not a constructor or null"');
shouldThrow('x = class extends "abc" { constructor() { } }; x.__proto__', '"TypeError: Class extends value abc is not a constructor or null"');
shouldNotThrow('baseWithBadPrototype = function () {}; baseWithBadPrototype.prototype = 3; new baseWithBadPrototype');
shouldThrow('x = class extends baseWithBadPrototype { constructor() { } }', '"TypeError: Class extends value does not have valid prototype property 3"');
shouldNotThrow('baseWithBadPrototype.prototype = "abc"');
......@@ -92,10 +92,10 @@ shouldBe('x = 1; namespace = {}; namespace.A = class { constructor() { } }; try
shouldBe('Object.getPrototypeOf((class { constructor () { } }).prototype)', 'Object.prototype');
shouldBe('Object.getPrototypeOf((class extends null { constructor () { super(); } }).prototype)', 'null');
shouldThrow('new (class extends undefined { constructor () { this } })', '"TypeError: Class extends value undefined is not a function or null"');
shouldThrow('new (class extends undefined { constructor () { super(); } })', '"TypeError: Class extends value undefined is not a function or null"');
shouldThrow('x = {}; new (class extends undefined { constructor () { return x; } })', '"TypeError: Class extends value undefined is not a function or null"');
shouldThrow('y = 12; new (class extends undefined { constructor () { return y; } })', '"TypeError: Class extends value undefined is not a function or null"');
shouldThrow('new (class extends undefined { constructor () { this } })', '"TypeError: Class extends value undefined is not a constructor or null"');
shouldThrow('new (class extends undefined { constructor () { super(); } })', '"TypeError: Class extends value undefined is not a constructor or null"');
shouldThrow('x = {}; new (class extends undefined { constructor () { return x; } })', '"TypeError: Class extends value undefined is not a constructor or null"');
shouldThrow('y = 12; new (class extends undefined { constructor () { return y; } })', '"TypeError: Class extends value undefined is not a constructor or null"');
shouldBeTrue ('class x {}; new (class extends null { constructor () { return new x; } }) instanceof x');
shouldThrow('new (class extends null { constructor () { this; } })', '"ReferenceError: this is not defined"');
shouldThrow('new (class extends null { constructor () { super(); } })', '"TypeError: super is not a constructor"');
......
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