[compiler] Force all calls to JS builtins to be lowered

Previously only Builtins declared TFJ or CPP in builtins-definitions.h
were converted to direct calls in ReduceJSCall. This allows all
builtins with JS linkage to be converted. To facilitate this, it adds
Builtins::HasJSLinkage(id) that returns true for any builtins with
JSTrampolineDescriptor as their call descriptor.

It also ensures that any JS functions installed by the bootstrapper are
also required to have JS linkage to catch early errors.

Change-Id: I2fddca41f9ab1c7c9633aa0ab4847a5c108e2bb2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1883549
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Dan Elphick <delphick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64698}
This commit is contained in:
Dan Elphick 2019-10-31 12:22:49 +00:00 committed by Commit Bot
parent ceb0aef09e
commit 1db94eddb8
8 changed files with 56 additions and 12 deletions

View File

@ -97,8 +97,8 @@ namespace internal {
ASM(JSEntry, Dummy) \
ASM(JSConstructEntry, Dummy) \
ASM(JSRunMicrotasksEntry, RunMicrotasksEntry) \
ASM(JSEntryTrampoline, Dummy) \
ASM(JSConstructEntryTrampoline, Dummy) \
ASM(JSEntryTrampoline, JSTrampoline) \
ASM(JSConstructEntryTrampoline, JSTrampoline) \
ASM(ResumeGeneratorTrampoline, ResumeGenerator) \
\
/* String helpers */ \
@ -116,7 +116,7 @@ namespace internal {
TFS(OrderedHashTableHealIndex, kTable, kIndex) \
\
/* Interpreter */ \
ASM(InterpreterEntryTrampoline, Dummy) \
ASM(InterpreterEntryTrampoline, JSTrampoline) \
ASM(InterpreterPushArgsThenCall, InterpreterPushArgsThenCall) \
ASM(InterpreterPushUndefinedAndArgsThenCall, InterpreterPushArgsThenCall) \
ASM(InterpreterPushArgsThenCallWithFinalSpread, InterpreterPushArgsThenCall) \
@ -522,12 +522,12 @@ namespace internal {
\
/* Function */ \
CPP(FunctionConstructor) \
ASM(FunctionPrototypeApply, Dummy) \
ASM(FunctionPrototypeApply, JSTrampoline) \
CPP(FunctionPrototypeBind) \
/* ES6 #sec-function.prototype.bind */ \
TFJ(FastFunctionPrototypeBind, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
ASM(FunctionPrototypeCall, Dummy) \
ASM(FunctionPrototypeCall, JSTrampoline) \
/* ES6 #sec-function.prototype-@@hasinstance */ \
TFJ(FunctionPrototypeHasInstance, 1, kReceiver, kV) \
/* ES6 #sec-function.prototype.tostring */ \
@ -796,8 +796,8 @@ namespace internal {
TFJ(PromiseAllSettledRejectElementClosure, 1, kReceiver, kValue) \
\
/* Reflect */ \
ASM(ReflectApply, Dummy) \
ASM(ReflectConstruct, Dummy) \
ASM(ReflectApply, JSTrampoline) \
ASM(ReflectConstruct, JSTrampoline) \
CPP(ReflectDefineProperty) \
CPP(ReflectGetOwnPropertyDescriptor) \
CPP(ReflectOwnKeys) \

View File

@ -188,6 +188,13 @@ Callable Builtins::CallableFor(Isolate* isolate, Name name) {
return Callable{code, CallInterfaceDescriptorFor(name)};
}
// static
bool Builtins::HasJSLinkage(int builtin_index) {
Name name = static_cast<Name>(builtin_index);
DCHECK_NE(BCH, Builtins::KindOf(name));
return CallInterfaceDescriptorFor(name) == JSTrampolineDescriptor{};
}
// static
const char* Builtins::name(int index) {
DCHECK(IsBuiltinId(index));

View File

@ -95,6 +95,7 @@ class Builtins {
static CallInterfaceDescriptor CallInterfaceDescriptorFor(Name name);
V8_EXPORT_PRIVATE static Callable CallableFor(Isolate* isolate, Name name);
static bool HasJSLinkage(int index);
static int GetStackParameterCount(Name name);

View File

@ -292,6 +292,10 @@ class V8_EXPORT_PRIVATE CallInterfaceDescriptor {
const char* DebugName() const;
bool operator==(const CallInterfaceDescriptor& other) const {
return data() == other.data();
}
protected:
const CallInterfaceDescriptorData* data() const { return data_; }

View File

@ -2440,7 +2440,6 @@ void JSHeapBroker::InitializeRefsMap() {
Builtins::kCallFunction_ReceiverIsNotNullOrUndefined,
Builtins::kCallFunction_ReceiverIsNullOrUndefined,
Builtins::kCloneFastJSArray,
Builtins::kCompileLazy,
Builtins::kConstructFunctionForwardVarargs,
Builtins::kForInFilter,
Builtins::kGetProperty,
@ -2457,8 +2456,8 @@ void JSHeapBroker::InitializeRefsMap() {
GetOrCreateData(b->builtin_handle(id));
}
}
for (int32_t id = 0; id < Builtins::builtin_count; ++id) {
if (Builtins::KindOf(id) == Builtins::TFJ) {
for (int32_t id = 0; id < Builtins::kFirstBytecodeHandler; ++id) {
if (Builtins::HasJSLinkage(id)) {
GetOrCreateData(b->builtin_handle(id));
}
}

View File

@ -1759,8 +1759,8 @@ Reduction JSTypedLowering::ReduceJSCall(Node* node) {
} else if (shared.HasBuiltinId() && Builtins::IsCpp(shared.builtin_id())) {
// Patch {node} to a direct CEntry call.
ReduceBuiltin(jsgraph(), node, shared.builtin_id(), arity, flags);
} else if (shared.HasBuiltinId() &&
Builtins::KindOf(shared.builtin_id()) == Builtins::TFJ) {
} else if (shared.HasBuiltinId()) {
DCHECK(Builtins::HasJSLinkage(shared.builtin_id()));
// Patch {node} to a direct code object call.
Callable callable = Builtins::CallableFor(
isolate(), static_cast<Builtins::Name>(shared.builtin_id()));

View File

@ -382,6 +382,8 @@ V8_NOINLINE Handle<JSFunction> CreateFunction(
Isolate* isolate, Handle<String> name, InstanceType type, int instance_size,
int inobject_properties, Handle<HeapObject> prototype,
Builtins::Name builtin_id) {
DCHECK(Builtins::HasJSLinkage(builtin_id));
Handle<JSFunction> result;
NewFunctionArgs args = NewFunctionArgs::ForBuiltinWithPrototype(
@ -412,6 +414,7 @@ V8_NOINLINE Handle<JSFunction> InstallFunction(
Isolate* isolate, Handle<JSObject> target, Handle<String> name,
InstanceType type, int instance_size, int inobject_properties,
Handle<HeapObject> prototype, Builtins::Name call) {
DCHECK(Builtins::HasJSLinkage(call));
Handle<JSFunction> function = CreateFunction(
isolate, name, type, instance_size, inobject_properties, prototype, call);
JSObject::AddProperty(isolate, target, name, function, DONT_ENUM);
@ -431,6 +434,7 @@ V8_NOINLINE Handle<JSFunction> SimpleCreateFunction(Isolate* isolate,
Handle<String> name,
Builtins::Name call,
int len, bool adapt) {
DCHECK(Builtins::HasJSLinkage(call));
NewFunctionArgs args = NewFunctionArgs::ForBuiltinWithoutPrototype(
name, call, LanguageMode::kStrict);
Handle<JSFunction> fun = isolate->factory()->NewFunction(args);

View File

@ -0,0 +1,29 @@
// Copyright 2019 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: --allow-natives-syntax
function check(x) { assertEquals(x, "foo"); }
var r = Realm.createAllowCrossRealmAccess();
var f = Realm.eval(r, `
function f(func) {
// The call to Function.prototype.apply is across native contexts so
// cannot be elided. However the compiler should be able to call the
// builtin directly rather than via the trampoline Code object. This isn't
// easy to test, but here we at least check that it doesn't crash due to
// calling a builtin Code object incorrectly (Function.Prototype.apply).
return func.apply(undefined, ["foo"]);
}
f;`);
%PrepareFunctionForOptimization(f);
f(check);
f(check);
%OptimizeFunctionOnNextCall(f);
f(check);