Commit 0058f82e authored by jochen's avatar jochen Committed by Commit bot

Add an API to create a detached global object

Such an object can be used to later create a context from it. It has to
have access checks with handlers enabled, as it cannot be accessed
otherwise.

BUG=chromium:618305
R=verwaest@chromium.org

Review-Url: https://codereview.chromium.org/2107673003
Cr-Commit-Position: refs/heads/master@{#37594}
parent 312d0149
......@@ -7158,14 +7158,35 @@ class V8_EXPORT Context {
*/
static Local<Context> New(
Isolate* isolate, ExtensionConfiguration* extensions = NULL,
Local<ObjectTemplate> global_template = Local<ObjectTemplate>(),
Local<Value> global_object = Local<Value>());
MaybeLocal<ObjectTemplate> global_template = MaybeLocal<ObjectTemplate>(),
MaybeLocal<Value> global_object = MaybeLocal<Value>());
static MaybeLocal<Context> FromSnapshot(
Isolate* isolate, size_t context_snapshot_index,
ExtensionConfiguration* extensions = NULL,
Local<ObjectTemplate> global_template = Local<ObjectTemplate>(),
Local<Value> global_object = Local<Value>());
ExtensionConfiguration* extensions = nullptr,
MaybeLocal<ObjectTemplate> global_template = MaybeLocal<ObjectTemplate>(),
MaybeLocal<Value> global_object = MaybeLocal<Value>());
/**
* Returns an global object that isn't backed by an actual context.
*
* The global template needs to have access checks with handlers installed.
* If an existing global object is passed in, the global object is detached
* from its context.
*
* Note that this is different from a detached context where all accesses to
* the global proxy will fail. Instead, the access check handlers are invoked.
*
* It is also not possible to detach an object returned by this method.
* Instead, the access check handlers need to return nothing to achieve the
* same effect.
*
* It is possible, however, the create a new context from the global object
* returned by this method.
*/
static MaybeLocal<Object> NewRemoteContext(
Isolate* isolate, Local<ObjectTemplate> global_template,
MaybeLocal<Value> global_object = MaybeLocal<Value>());
/**
* Sets the security token for the context. To access an object in
......
......@@ -5643,20 +5643,51 @@ const char* v8::V8::GetVersion() {
return i::Version::GetVersion();
}
static i::Handle<i::Context> CreateEnvironment(
template <typename ObjectType>
struct InvokeBootstrapper;
template <>
struct InvokeBootstrapper<i::Context> {
i::Handle<i::Context> Invoke(
i::Isolate* isolate, i::MaybeHandle<i::JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_object_template,
v8::ExtensionConfiguration* extensions, size_t context_snapshot_index) {
return isolate->bootstrapper()->CreateEnvironment(
maybe_global_proxy, global_object_template, extensions,
context_snapshot_index);
}
};
template <>
struct InvokeBootstrapper<i::JSGlobalProxy> {
i::Handle<i::JSGlobalProxy> Invoke(
i::Isolate* isolate, i::MaybeHandle<i::JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_object_template,
v8::ExtensionConfiguration* extensions, size_t context_snapshot_index) {
USE(extensions);
USE(context_snapshot_index);
return isolate->bootstrapper()->NewRemoteContext(maybe_global_proxy,
global_object_template);
}
};
template <typename ObjectType>
static i::Handle<ObjectType> CreateEnvironment(
i::Isolate* isolate, v8::ExtensionConfiguration* extensions,
v8::Local<ObjectTemplate> global_template,
v8::Local<Value> maybe_global_proxy, size_t context_snapshot_index) {
i::Handle<i::Context> env;
v8::MaybeLocal<ObjectTemplate> maybe_global_template,
v8::MaybeLocal<Value> maybe_global_proxy, size_t context_snapshot_index) {
i::Handle<ObjectType> result;
// Enter V8 via an ENTER_V8 scope.
{
ENTER_V8(isolate);
v8::Local<ObjectTemplate> proxy_template = global_template;
v8::Local<ObjectTemplate> proxy_template;
i::Handle<i::FunctionTemplateInfo> proxy_constructor;
i::Handle<i::FunctionTemplateInfo> global_constructor;
if (!global_template.IsEmpty()) {
if (!maybe_global_template.IsEmpty()) {
v8::Local<v8::ObjectTemplate> global_template =
maybe_global_template.ToLocalChecked();
// Make sure that the global_template has a constructor.
global_constructor = EnsureConstructor(isolate, *global_template);
......@@ -5684,17 +5715,18 @@ static i::Handle<i::Context> CreateEnvironment(
}
}
i::Handle<i::Object> proxy = Utils::OpenHandle(*maybe_global_proxy, true);
i::MaybeHandle<i::JSGlobalProxy> maybe_proxy;
if (!proxy.is_null()) {
maybe_proxy = i::Handle<i::JSGlobalProxy>::cast(proxy);
if (!maybe_global_proxy.IsEmpty()) {
maybe_proxy = i::Handle<i::JSGlobalProxy>::cast(
Utils::OpenHandle(*maybe_global_proxy.ToLocalChecked()));
}
// Create the environment.
env = isolate->bootstrapper()->CreateEnvironment(
maybe_proxy, proxy_template, extensions, context_snapshot_index);
InvokeBootstrapper<ObjectType> invoke;
result = invoke.Invoke(isolate, maybe_proxy, proxy_template, extensions,
context_snapshot_index);
// Restore the access check info on the global template.
if (!global_template.IsEmpty()) {
if (!maybe_global_template.IsEmpty()) {
DCHECK(!global_constructor.is_null());
DCHECK(!proxy_constructor.is_null());
global_constructor->set_access_check_info(
......@@ -5705,13 +5737,13 @@ static i::Handle<i::Context> CreateEnvironment(
}
// Leave V8.
return env;
return result;
}
Local<Context> NewContext(v8::Isolate* external_isolate,
v8::ExtensionConfiguration* extensions,
v8::Local<ObjectTemplate> global_template,
v8::Local<Value> global_object,
v8::MaybeLocal<ObjectTemplate> global_template,
v8::MaybeLocal<Value> global_object,
size_t context_snapshot_index) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external_isolate);
LOG_API(isolate, Context, New);
......@@ -5719,8 +5751,8 @@ Local<Context> NewContext(v8::Isolate* external_isolate,
ExtensionConfiguration no_extensions;
if (extensions == NULL) extensions = &no_extensions;
i::Handle<i::Context> env =
CreateEnvironment(isolate, extensions, global_template, global_object,
context_snapshot_index);
CreateEnvironment<i::Context>(isolate, extensions, global_template,
global_object, context_snapshot_index);
if (env.is_null()) {
if (isolate->has_pending_exception()) {
isolate->OptionalRescheduleException(true);
......@@ -5732,8 +5764,8 @@ Local<Context> NewContext(v8::Isolate* external_isolate,
Local<Context> v8::Context::New(v8::Isolate* external_isolate,
v8::ExtensionConfiguration* extensions,
v8::Local<ObjectTemplate> global_template,
v8::Local<Value> global_object) {
v8::MaybeLocal<ObjectTemplate> global_template,
v8::MaybeLocal<Value> global_object) {
return NewContext(external_isolate, extensions, global_template,
global_object, 0);
}
......@@ -5741,7 +5773,8 @@ Local<Context> v8::Context::New(v8::Isolate* external_isolate,
MaybeLocal<Context> v8::Context::FromSnapshot(
v8::Isolate* external_isolate, size_t context_snapshot_index,
v8::ExtensionConfiguration* extensions,
v8::Local<ObjectTemplate> global_template, v8::Local<Value> global_object) {
v8::MaybeLocal<ObjectTemplate> global_template,
v8::MaybeLocal<Value> global_object) {
if (!i::Snapshot::HasContextSnapshot(
reinterpret_cast<i::Isolate*>(external_isolate),
context_snapshot_index)) {
......@@ -5751,6 +5784,36 @@ MaybeLocal<Context> v8::Context::FromSnapshot(
global_object, context_snapshot_index);
}
MaybeLocal<Object> v8::Context::NewRemoteContext(
v8::Isolate* external_isolate, v8::Local<ObjectTemplate> global_template,
v8::MaybeLocal<v8::Value> global_object) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external_isolate);
LOG_API(isolate, Context, NewRemoteContext);
i::HandleScope scope(isolate);
i::Handle<i::FunctionTemplateInfo> global_constructor =
EnsureConstructor(isolate, *global_template);
Utils::ApiCheck(global_constructor->needs_access_check(),
"v8::Context::NewRemoteContext",
"Global template needs to have access checks enabled.");
i::Handle<i::AccessCheckInfo> access_check_info = i::handle(
i::AccessCheckInfo::cast(global_constructor->access_check_info()),
isolate);
Utils::ApiCheck(access_check_info->named_interceptor() != nullptr,
"v8::Context::NewRemoteContext",
"Global template needs to have access check handlers.");
i::Handle<i::JSGlobalProxy> global_proxy =
CreateEnvironment<i::JSGlobalProxy>(isolate, nullptr, global_template,
global_object, 0);
if (global_proxy.is_null()) {
if (isolate->has_pending_exception()) {
isolate->OptionalRescheduleException(true);
}
return MaybeLocal<Object>();
}
return Utils::ToLocal(
scope.CloseAndEscape(i::Handle<i::JSObject>::cast(global_proxy)));
}
void v8::Context::SetSecurityToken(Local<Value> token) {
i::Handle<i::Context> env = Utils::OpenHandle(this);
i::Handle<i::Object> token_handle = Utils::OpenHandle(*token);
......
......@@ -141,6 +141,8 @@ class Genesis BASE_EMBEDDED {
v8::Local<v8::ObjectTemplate> global_proxy_template,
v8::ExtensionConfiguration* extensions, size_t context_snapshot_index,
GlobalContextType context_type);
Genesis(Isolate* isolate, MaybeHandle<JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_proxy_template);
~Genesis() { }
Isolate* isolate() const { return isolate_; }
......@@ -149,6 +151,8 @@ class Genesis BASE_EMBEDDED {
Handle<Context> result() { return result_; }
Handle<JSGlobalProxy> global_proxy() { return global_proxy_; }
private:
Handle<Context> native_context() { return native_context_; }
......@@ -302,6 +306,7 @@ class Genesis BASE_EMBEDDED {
Isolate* isolate_;
Handle<Context> result_;
Handle<Context> native_context_;
Handle<JSGlobalProxy> global_proxy_;
// Function maps. Function maps are created initially with a read only
// prototype for the processing of JS builtins. Later the function maps are
......@@ -337,6 +342,15 @@ Handle<Context> Bootstrapper::CreateEnvironment(
return scope.CloseAndEscape(env);
}
Handle<JSGlobalProxy> Bootstrapper::NewRemoteContext(
MaybeHandle<JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_proxy_template) {
HandleScope scope(isolate_);
Genesis genesis(isolate_, maybe_global_proxy, global_proxy_template);
Handle<JSGlobalProxy> global_proxy = genesis.global_proxy();
if (global_proxy.is_null()) return Handle<JSGlobalProxy>();
return scope.CloseAndEscape(global_proxy);
}
static void SetObjectPrototype(Handle<JSObject> object, Handle<Object> proto) {
// object.__proto__ = proto;
......@@ -3884,6 +3898,8 @@ Genesis::Genesis(Isolate* isolate,
: isolate_(isolate), active_(isolate->bootstrapper()) {
NoTrackDoubleFieldsForSerializerScope disable_scope(isolate);
result_ = Handle<Context>::null();
global_proxy_ = Handle<JSGlobalProxy>::null();
// Before creating the roots we must save the context and restore it
// on all function exits.
SaveContext saved_context(isolate);
......@@ -3992,6 +4008,67 @@ Genesis::Genesis(Isolate* isolate,
result_ = native_context();
}
Genesis::Genesis(Isolate* isolate,
MaybeHandle<JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_proxy_template)
: isolate_(isolate), active_(isolate->bootstrapper()) {
NoTrackDoubleFieldsForSerializerScope disable_scope(isolate);
result_ = Handle<Context>::null();
global_proxy_ = Handle<JSGlobalProxy>::null();
// Before creating the roots we must save the context and restore it
// on all function exits.
SaveContext saved_context(isolate);
// During genesis, the boilerplate for stack overflow won't work until the
// environment has been at least partially initialized. Add a stack check
// before entering JS code to catch overflow early.
StackLimitCheck check(isolate);
if (check.HasOverflowed()) {
isolate->StackOverflow();
return;
}
Handle<JSGlobalProxy> global_proxy;
if (!maybe_global_proxy.ToHandle(&global_proxy)) {
global_proxy = factory()->NewUninitializedJSGlobalProxy();
}
// CreateNewGlobals.
Handle<ObjectTemplateInfo> global_proxy_data =
v8::Utils::OpenHandle(*global_proxy_template);
Handle<FunctionTemplateInfo> global_constructor(
FunctionTemplateInfo::cast(global_proxy_data->constructor()));
Handle<SharedFunctionInfo> shared =
FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate,
global_constructor);
Handle<Map> initial_map =
CreateSloppyFunctionMap(FUNCTION_WITH_WRITEABLE_PROTOTYPE);
Handle<JSFunction> global_proxy_function =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
initial_map, shared, factory()->undefined_value());
DCHECK_EQ(global_proxy_data->internal_field_count(), 0);
Handle<Map> global_proxy_map = isolate->factory()->NewMap(
JS_GLOBAL_PROXY_TYPE, JSGlobalProxy::kSize, FAST_HOLEY_SMI_ELEMENTS);
JSFunction::SetInitialMap(global_proxy_function, global_proxy_map,
factory()->null_value());
global_proxy_map->set_is_access_check_needed(true);
global_proxy_map->set_is_callable();
global_proxy_map->set_is_constructor(true);
global_proxy_map->set_has_hidden_prototype(true);
Handle<String> global_name = factory()->global_string();
global_proxy_function->shared()->set_instance_class_name(*global_name);
factory()->ReinitializeJSGlobalProxy(global_proxy, global_proxy_function);
// HookUpGlobalProxy.
global_proxy->set_native_context(*factory()->null_value());
// DetachGlobal.
SetObjectPrototype(global_proxy, factory()->null_value());
global_proxy_ = global_proxy;
}
// Support for thread preemption.
......
......@@ -82,6 +82,10 @@ class Bootstrapper final {
v8::ExtensionConfiguration* extensions, size_t context_snapshot_index,
GlobalContextType context_type = FULL_CONTEXT);
Handle<JSGlobalProxy> NewRemoteContext(
MaybeHandle<JSGlobalProxy> maybe_global_proxy,
v8::Local<v8::ObjectTemplate> global_object_template);
// Detach the environment from its outer global object.
void DetachGlobal(Handle<Context> env);
......
......@@ -531,6 +531,7 @@ class RuntimeCallTimer {
V(BooleanObject_BooleanValue) \
V(BooleanObject_New) \
V(Context_New) \
V(Context_NewRemoteContext) \
V(DataView_New) \
V(Date_DateTimeConfigurationChangeNotification) \
V(Date_New) \
......
......@@ -1217,19 +1217,20 @@ DEFINE_ERROR(SyntaxError, syntax_error)
DEFINE_ERROR(TypeError, type_error)
#undef DEFINE_ERROR
Handle<JSFunction> Factory::NewFunction(Handle<Map> map,
Handle<SharedFunctionInfo> info,
Handle<Context> context,
Handle<Object> context_or_undefined,
PretenureFlag pretenure) {
AllocationSpace space = pretenure == TENURED ? OLD_SPACE : NEW_SPACE;
Handle<JSFunction> function = New<JSFunction>(map, space);
DCHECK(context_or_undefined->IsContext() ||
context_or_undefined->IsUndefined(isolate()));
function->initialize_properties();
function->initialize_elements();
function->set_shared(*info);
function->set_code(info->code());
function->set_context(*context);
function->set_context(*context_or_undefined);
function->set_prototype_or_initial_map(*the_hole_value());
function->set_literals(LiteralsArray::cast(*empty_literals_array()));
function->set_next_function_link(*undefined_value(), SKIP_WRITE_BARRIER);
......@@ -1362,20 +1363,21 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
pretenure);
}
Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
Handle<Map> initial_map, Handle<SharedFunctionInfo> info,
Handle<Context> context, PretenureFlag pretenure) {
Handle<Object> context_or_undefined, PretenureFlag pretenure) {
DCHECK_EQ(JS_FUNCTION_TYPE, initial_map->instance_type());
Handle<JSFunction> result =
NewFunction(initial_map, info, context, pretenure);
NewFunction(initial_map, info, context_or_undefined, pretenure);
if (info->ic_age() != isolate()->heap()->global_ic_age()) {
info->ResetForNewContext(isolate()->heap()->global_ic_age());
}
// Give compiler a chance to pre-initialize.
Compiler::PostInstantiation(result, pretenure);
if (context_or_undefined->IsContext()) {
// Give compiler a chance to pre-initialize.
Compiler::PostInstantiation(result, pretenure);
}
return result;
}
......
......@@ -502,6 +502,10 @@ class Factory final {
Handle<JSGlobalProxy> NewUninitializedJSGlobalProxy();
Handle<JSFunction> NewFunction(Handle<Map> map,
Handle<SharedFunctionInfo> info,
Handle<Object> context_or_undefined,
PretenureFlag pretenure = TENURED);
Handle<JSFunction> NewFunction(Handle<String> name, Handle<Code> code,
Handle<Object> prototype,
bool is_strict = false);
......@@ -512,7 +516,7 @@ class Factory final {
Handle<JSFunction> NewFunctionFromSharedFunctionInfo(
Handle<Map> initial_map, Handle<SharedFunctionInfo> function_info,
Handle<Context> context, PretenureFlag pretenure = TENURED);
Handle<Object> context_or_undefined, PretenureFlag pretenure = TENURED);
Handle<JSFunction> NewFunctionFromSharedFunctionInfo(
Handle<SharedFunctionInfo> function_info, Handle<Context> context,
......@@ -709,12 +713,6 @@ class Factory final {
// Update the cache with a new number-string pair.
void SetNumberStringCache(Handle<Object> number, Handle<String> string);
// Creates a function initialized with a shared part.
Handle<JSFunction> NewFunction(Handle<Map> map,
Handle<SharedFunctionInfo> info,
Handle<Context> context,
PretenureFlag pretenure = TENURED);
// Create a JSArray with no elements and no length.
Handle<JSArray> NewJSArray(ElementsKind elements_kind,
PretenureFlag pretenure = NOT_TENURED);
......
This diff is collapsed.
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