Commit ce1366a2 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by V8 LUCI CQ

Make JSReceiver::GetFunctionRealm iterative

instead of recursive. JS code can construct very long chains of
nested bound functions or proxies, where the previous recursive
implementation could run out of stack space.

Fixed: chromium:1214616
Change-Id: I764718f03030d22c0873b3ed05277d4317789093
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2933668
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74981}
parent 15e48957
......@@ -186,14 +186,6 @@ bool JSFunction::CanDiscardCompiled() const {
return (result & kJSFunctionCodeKindsMask) != 0;
}
// static
MaybeHandle<NativeContext> JSBoundFunction::GetFunctionRealm(
Handle<JSBoundFunction> function) {
DCHECK(function->map().is_constructor());
return JSReceiver::GetFunctionRealm(
handle(function->bound_target_function(), function->GetIsolate()));
}
// static
MaybeHandle<String> JSBoundFunction::GetName(Isolate* isolate,
Handle<JSBoundFunction> function) {
......@@ -261,13 +253,6 @@ Handle<Object> JSFunction::GetName(Isolate* isolate,
return handle(function->shared().Name(), isolate);
}
// static
Handle<NativeContext> JSFunction::GetFunctionRealm(
Handle<JSFunction> function) {
DCHECK(function->map().is_constructor());
return handle(function->context().native_context(), function->GetIsolate());
}
// static
void JSFunction::EnsureClosureFeedbackCellArray(
Handle<JSFunction> function, bool reset_budget_for_feedback_allocation) {
......
......@@ -37,8 +37,6 @@ class JSBoundFunction
Handle<JSBoundFunction> function);
static Maybe<int> GetLength(Isolate* isolate,
Handle<JSBoundFunction> function);
static MaybeHandle<NativeContext> GetFunctionRealm(
Handle<JSBoundFunction> function);
// Dispatched behavior.
DECL_PRINTER(JSBoundFunction)
......@@ -77,7 +75,6 @@ class JSFunction : public JSFunctionOrBoundFunction {
inline int length();
static Handle<Object> GetName(Isolate* isolate, Handle<JSFunction> function);
static Handle<NativeContext> GetFunctionRealm(Handle<JSFunction> function);
// [code]: The generated code object for this function. Executed
// when the function is invoked, e.g. foo() or new foo(). See
......
......@@ -567,20 +567,37 @@ MaybeHandle<NativeContext> JSReceiver::GetCreationContext() {
// static
MaybeHandle<NativeContext> JSReceiver::GetFunctionRealm(
Handle<JSReceiver> receiver) {
if (receiver->IsJSProxy()) {
return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
}
if (receiver->IsJSFunction()) {
return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
}
if (receiver->IsJSBoundFunction()) {
return JSBoundFunction::GetFunctionRealm(
Handle<JSBoundFunction>::cast(receiver));
}
return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
Isolate* isolate = receiver->GetIsolate();
// This is implemented as a loop because it's possible to construct very
// long chains of bound functions or proxies where a recursive implementation
// would run out of stack space.
DisallowGarbageCollection no_gc;
JSReceiver current = *receiver;
do {
DCHECK(current.map().is_constructor());
if (current.IsJSProxy()) {
JSProxy proxy = JSProxy::cast(current);
if (proxy.IsRevoked()) {
AllowGarbageCollection allow_allocating_errors;
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kProxyRevoked),
NativeContext);
}
current = JSReceiver::cast(proxy.target());
continue;
}
if (current.IsJSFunction()) {
JSFunction function = JSFunction::cast(current);
return handle(function.context().native_context(), isolate);
}
if (current.IsJSBoundFunction()) {
JSBoundFunction function = JSBoundFunction::cast(current);
current = function.bound_target_function();
continue;
}
JSObject object = JSObject::cast(current);
DCHECK(!object.IsJSFunction());
return object.GetCreationContext();
} while (true);
}
// static
......@@ -3139,13 +3156,6 @@ Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
return Map::TransitionElementsTo(object->GetIsolate(), map, to_kind);
}
// static
MaybeHandle<NativeContext> JSObject::GetFunctionRealm(Handle<JSObject> object) {
DCHECK(object->map().is_constructor());
DCHECK(!object->IsJSFunction());
return object->GetCreationContext();
}
void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
DCHECK(object->map().GetInObjectProperties() == map->GetInObjectProperties());
ElementsKind obj_kind = object->map().elements_kind();
......
......@@ -304,8 +304,6 @@ class JSObject : public TorqueGeneratedJSObject<JSObject, JSReceiver> {
Handle<JSFunction> constructor, Handle<JSReceiver> new_target,
Handle<AllocationSite> site);
static MaybeHandle<NativeContext> GetFunctionRealm(Handle<JSObject> object);
// 9.1.12 ObjectCreate ( proto [ , internalSlotsList ] )
// Notice: This is NOT 19.1.2.2 Object.create ( O, Properties )
static V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> ObjectCreate(
......
......@@ -23,8 +23,6 @@ class JSProxy : public TorqueGeneratedJSProxy<JSProxy, JSReceiver> {
Handle<Object>,
Handle<Object>);
static MaybeHandle<NativeContext> GetFunctionRealm(Handle<JSProxy> proxy);
V8_INLINE bool IsRevoked() const;
static void Revoke(Handle<JSProxy> proxy);
......
......@@ -3216,19 +3216,6 @@ MaybeHandle<JSProxy> JSProxy::New(Isolate* isolate, Handle<Object> target,
Handle<JSReceiver>::cast(handler));
}
// static
MaybeHandle<NativeContext> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
DCHECK(proxy->map().is_constructor());
if (proxy->IsRevoked()) {
THROW_NEW_ERROR(proxy->GetIsolate(),
NewTypeError(MessageTemplate::kProxyRevoked),
NativeContext);
}
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()),
proxy->GetIsolate());
return JSReceiver::GetFunctionRealm(target);
}
Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
PropertyDescriptor desc;
Maybe<bool> found = JSProxy::GetOwnPropertyDescriptor(
......
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