Commit 562bb582 authored by jochen's avatar jochen Committed by Commit bot

Add API to create a "remote" instance of a given FunctionTemplate

BUG=chromium:618305
R=verwaest@chromium.org
CC=dcheng@chromium.org,haraken@chromium.org

Review-Url: https://codereview.chromium.org/2162443002
Cr-Commit-Position: refs/heads/master@{#37867}
parent a451bd1a
......@@ -4520,6 +4520,15 @@ class V8_EXPORT FunctionTemplate : public Template {
V8_WARN_UNUSED_RESULT MaybeLocal<Function> GetFunction(
Local<Context> context);
/**
* Similar to Context::NewRemoteContext, this creates an instance that
* isn't backed by an actual object.
*
* The InstanceTemplate of this FunctionTemplate must have access checks with
* handlers installed.
*/
V8_WARN_UNUSED_RESULT MaybeLocal<Object> NewRemoteInstance();
/**
* Set the call-handler callback for a FunctionTemplate. This
* callback is called whenever the function created from this
......
......@@ -486,6 +486,35 @@ MaybeHandle<JSObject> ApiNatives::InstantiateObject(
return ::v8::internal::InstantiateObject(isolate, data, new_target, false);
}
MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
Handle<ObjectTemplateInfo> data) {
Isolate* isolate = data->GetIsolate();
InvokeScope invoke_scope(isolate);
Handle<FunctionTemplateInfo> constructor(
FunctionTemplateInfo::cast(data->constructor()));
Handle<SharedFunctionInfo> shared =
FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, constructor);
Handle<Map> initial_map = isolate->factory()->CreateSloppyFunctionMap(
FUNCTION_WITH_WRITEABLE_PROTOTYPE);
Handle<JSFunction> object_function =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
initial_map, shared, isolate->factory()->undefined_value());
Handle<Map> object_map = isolate->factory()->NewMap(
JS_SPECIAL_API_OBJECT_TYPE,
JSObject::kHeaderSize + data->internal_field_count() * kPointerSize,
FAST_HOLEY_SMI_ELEMENTS);
JSFunction::SetInitialMap(object_function, object_map,
isolate->factory()->null_value());
object_map->set_is_access_check_needed(true);
object_map->set_is_callable();
object_map->set_is_constructor(true);
Handle<JSObject> object = isolate->factory()->NewJSObject(object_function);
JSObject::ForceSetPrototype(object, isolate->factory()->null_value());
return object;
}
void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
Handle<Name> name, Handle<Object> value,
......
......@@ -26,6 +26,9 @@ class ApiNatives {
Handle<ObjectTemplateInfo> data,
Handle<JSReceiver> new_target = Handle<JSReceiver>());
MUST_USE_RESULT static MaybeHandle<JSObject> InstantiateRemoteObject(
Handle<ObjectTemplateInfo> data);
enum ApiInstanceType {
JavaScriptObjectType,
GlobalObjectType,
......
......@@ -5953,6 +5953,32 @@ Local<v8::Function> FunctionTemplate::GetFunction() {
RETURN_TO_LOCAL_UNCHECKED(GetFunction(context), Function);
}
MaybeLocal<v8::Object> FunctionTemplate::NewRemoteInstance() {
auto self = Utils::OpenHandle(this);
i::Isolate* isolate = self->GetIsolate();
LOG_API(isolate, FunctionTemplate, NewRemoteInstance);
i::HandleScope scope(isolate);
i::Handle<i::FunctionTemplateInfo> constructor =
EnsureConstructor(isolate, *InstanceTemplate());
Utils::ApiCheck(constructor->needs_access_check(),
"v8::FunctionTemplate::NewRemoteInstance",
"InstanceTemplate needs to have access checks enabled.");
i::Handle<i::AccessCheckInfo> access_check_info = i::handle(
i::AccessCheckInfo::cast(constructor->access_check_info()), isolate);
Utils::ApiCheck(access_check_info->named_interceptor() != nullptr,
"v8::FunctionTemplate::NewRemoteInstance",
"InstanceTemplate needs to have access check handlers.");
i::Handle<i::JSObject> object;
if (!i::ApiNatives::InstantiateRemoteObject(
Utils::OpenHandle(*InstanceTemplate()))
.ToHandle(&object)) {
if (isolate->has_pending_exception()) {
isolate->OptionalRescheduleException(true);
}
return MaybeLocal<Object>();
}
return Utils::ToLocal(scope.CloseAndEscape(object));
}
bool FunctionTemplate::HasInstance(v8::Local<v8::Value> value) {
auto self = Utils::OpenHandle(this);
......
......@@ -547,6 +547,7 @@ class RuntimeCallTimer {
V(Function_NewInstance) \
V(FunctionTemplate_GetFunction) \
V(FunctionTemplate_New) \
V(FunctionTemplate_NewRemoteInstance) \
V(FunctionTemplate_NewWithFastHandler) \
V(Int16Array_New) \
V(Int32Array_New) \
......
......@@ -181,6 +181,10 @@ void CheckCrossContextAccess(v8::Isolate* isolate,
"[\"7\",\"cross_context_int\"]");
}
void Ctor(const v8::FunctionCallbackInfo<v8::Value>& info) {
CHECK(info.IsConstructCall());
}
} // namespace
TEST(AccessCheckWithInterceptor) {
......@@ -276,3 +280,26 @@ TEST(NewRemoteContext) {
CheckCanRunScriptInContext(isolate, context5);
}
}
TEST(NewRemoteInstance) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
v8::Local<v8::FunctionTemplate> tmpl =
v8::FunctionTemplate::New(isolate, Ctor);
v8::Local<v8::ObjectTemplate> instance = tmpl->InstanceTemplate();
instance->SetAccessCheckCallbackAndHandler(
AccessCheck,
v8::NamedPropertyHandlerConfiguration(
NamedGetter, NamedSetter, NamedQuery, NamedDeleter, NamedEnumerator),
v8::IndexedPropertyHandlerConfiguration(IndexedGetter, IndexedSetter,
IndexedQuery, IndexedDeleter,
IndexedEnumerator));
tmpl->SetNativeDataProperty(
v8_str("all_can_read"), Return42, nullptr, v8::Local<v8::Value>(),
v8::None, v8::Local<v8::AccessorSignature>(), v8::ALL_CAN_READ);
v8::Local<v8::Object> obj = tmpl->NewRemoteInstance().ToLocalChecked();
v8::Local<v8::Context> context = v8::Context::New(isolate);
CheckCrossContextAccess(isolate, context, obj);
}
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