Commit d346834f authored by domenic's avatar domenic Committed by Commit bot

Implement V8 extras utils object

This adds a utils object meant specifically for V8 extras, presenting a limited
API surface for doing things that would otherwise require %-functions.

BUG=v8:4276
LOG=Y
R=jochen@chromium.org,yangguo@chromium.org

Review URL: https://codereview.chromium.org/1343113003

Cr-Commit-Position: refs/heads/master@{#30773}
parent d4e1299f
......@@ -1526,9 +1526,13 @@ bool Bootstrapper::CompileBuiltin(Isolate* isolate, int index) {
Vector<const char> name = Natives::GetScriptName(index);
Handle<String> source_code =
isolate->bootstrapper()->SourceLookup<Natives>(index);
// We pass in extras_utils so that builtin code can set it up for later use
// by actual extras code, compiled with CompileExtraBuiltin.
Handle<Object> global = isolate->global_object();
Handle<Object> utils = isolate->natives_utils_object();
Handle<Object> args[] = {global, utils};
Handle<Object> extras_utils = isolate->extras_utils_object();
Handle<Object> args[] = {global, utils, extras_utils};
return Bootstrapper::CompileNative(
isolate, name, Handle<JSObject>(isolate->native_context()->builtins()),
......@@ -1557,7 +1561,8 @@ bool Bootstrapper::CompileExtraBuiltin(Isolate* isolate, int index) {
isolate->bootstrapper()->SourceLookup<ExtraNatives>(index);
Handle<Object> global = isolate->global_object();
Handle<Object> binding = isolate->extras_binding_object();
Handle<Object> args[] = {global, binding};
Handle<Object> extras_utils = isolate->extras_utils_object();
Handle<Object> args[] = {global, binding, extras_utils};
return Bootstrapper::CompileNative(
isolate, name, Handle<JSObject>(isolate->native_context()->builtins()),
source_code, arraysize(args), args);
......@@ -1572,7 +1577,8 @@ bool Bootstrapper::CompileExperimentalExtraBuiltin(Isolate* isolate,
isolate->bootstrapper()->SourceLookup<ExperimentalExtraNatives>(index);
Handle<Object> global = isolate->global_object();
Handle<Object> binding = isolate->extras_binding_object();
Handle<Object> args[] = {global, binding};
Handle<Object> extras_utils = isolate->extras_utils_object();
Handle<Object> args[] = {global, binding, extras_utils};
return Bootstrapper::CompileNative(
isolate, name, Handle<JSObject>(isolate->native_context()->builtins()),
source_code, arraysize(args), args);
......@@ -2025,6 +2031,14 @@ bool Genesis::InstallNatives(ContextType context_type) {
"utils container for native scripts");
native_context()->set_natives_utils_object(*utils);
// Set up the extras utils object as a shared container between native
// scripts and extras. (Extras consume things added there by native scripts.)
Handle<JSObject> extras_utils =
factory()->NewJSObject(isolate()->object_function());
native_context()->set_extras_utils_object(*extras_utils);
InstallInternalArray(extras_utils, "InternalPackedArray", FAST_ELEMENTS);
int builtin_index = Natives::GetDebuggerCount();
// Only run prologue.js and runtime.js at this point.
DCHECK_EQ(builtin_index, Natives::GetIndex("prologue"));
......@@ -2585,8 +2599,6 @@ bool Genesis::InstallExtraNatives() {
Handle<JSObject> extras_binding =
factory()->NewJSObject(isolate()->object_function());
JSObject::NormalizeProperties(extras_binding, CLEAR_INOBJECT_PROPERTIES, 2,
"container for binding to/from extra natives");
native_context()->set_extras_binding_object(*extras_binding);
for (int i = ExtraNatives::GetDebuggerCount();
......
......@@ -188,6 +188,7 @@ enum BindingFlags {
V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object, \
error_message_for_code_gen_from_strings) \
V(EXTRAS_EXPORTS_OBJECT_INDEX, JSObject, extras_binding_object) \
V(EXTRAS_UTILS_OBJECT_INDEX, JSObject, extras_utils_object) \
V(FAST_ALIASED_ARGUMENTS_MAP_INDEX, Map, fast_aliased_arguments_map) \
V(FLOAT32_ARRAY_FUN_INDEX, JSFunction, float32_array_fun) \
V(FLOAT32X4_FUNCTION_INDEX, JSFunction, float32x4_function) \
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(function(global, utils) {
(function(global, utils, extrasUtils) {
"use strict";
......@@ -267,4 +267,49 @@ utils.PostDebug = PostDebug;
%ToFastProperties(utils);
// -----------------------------------------------------------------------
%OptimizeObjectForAddingMultipleProperties(extrasUtils, 5);
extrasUtils.logStackTrace = function logStackTrace() {
%DebugTrace();
};
extrasUtils.log = function log() {
let message = '';
for (const arg of arguments) {
message += arg;
}
%GlobalPrint(message);
};
// Extras need the ability to store private state on their objects without
// exposing it to the outside world.
extrasUtils.createPrivateSymbol = function createPrivateSymbol(name) {
return %CreatePrivateSymbol(name);
};
// These functions are key for safe meta-programming:
// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
//
// Technically they could all be derived from combinations of
// Function.prototype.{bind,call,apply} but that introduces lots of layers of
// indirection and slowness given how un-optimized bind is.
extrasUtils.simpleBind = function simpleBind(func, thisArg) {
return function() {
return %Apply(func, thisArg, arguments, 0, arguments.length);
};
};
extrasUtils.uncurryThis = function uncurryThis(func) {
return function(thisArg) {
return %Apply(func, thisArg, arguments, 1, arguments.length - 1);
};
};
%ToFastProperties(extrasUtils);
})
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(function(global, utils) {
(function(global, utils, extrasUtils) {
"use strict";
......@@ -388,4 +388,13 @@ utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [
"promise_then", PromiseThen,
]);
// This allows extras to create promises quickly without building extra
// resolve/reject closures, and allows them to later resolve and reject any
// promise without having to hold on to those closures forever.
utils.InstallFunctions(extrasUtils, 0, [
"createPromise", PromiseCreate,
"resolvePromise", PromiseResolve,
"rejectPromise", PromiseReject
]);
})
......@@ -21700,6 +21700,45 @@ TEST(ExperimentalExtras) {
}
TEST(ExtrasUtilsObject) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope handle_scope(isolate);
LocalContext env;
v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
auto func = binding->Get(v8_str("testExtraCanUseUtils")).As<v8::Function>();
auto undefined = v8::Undefined(isolate);
auto result = func->Call(undefined, 0, {}).As<v8::Object>();
auto private_symbol = result->Get(v8_str("privateSymbol")).As<v8::Symbol>();
i::Handle<i::Symbol> ips = v8::Utils::OpenHandle(*private_symbol);
CHECK_EQ(true, ips->IsPrivate());
CompileRun("var result = 0; function store(x) { result = x; }");
auto store = CompileRun("store").As<v8::Function>();
auto fulfilled_promise =
result->Get(v8_str("fulfilledPromise")).As<v8::Promise>();
fulfilled_promise->Then(store);
isolate->RunMicrotasks();
CHECK_EQ(1, CompileRun("result")->Int32Value());
auto fulfilled_promise_2 =
result->Get(v8_str("fulfilledPromise2")).As<v8::Promise>();
fulfilled_promise_2->Then(store);
isolate->RunMicrotasks();
CHECK_EQ(2, CompileRun("result")->Int32Value());
auto rejected_promise =
result->Get(v8_str("rejectedPromise")).As<v8::Promise>();
rejected_promise->Catch(store);
isolate->RunMicrotasks();
CHECK_EQ(3, CompileRun("result")->Int32Value());
}
TEST(Map) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);
......
......@@ -2,13 +2,53 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(function (global, binding) {
(function (global, binding, v8) {
'use strict';
binding.testExtraShouldReturnFive = function () {
binding.testExtraShouldReturnFive = function() {
return 5;
};
binding.testExtraShouldCallToRuntime = function() {
return binding.runtime(3);
};
// Exercise all of the extras utils:
// - v8.createPrivateSymbol
// - v8.simpleBind, v8.uncurryThis
// - v8.InternalPackedArray
// - v8.createPromise, v8.resolvePromise, v8.rejectPromise
const Object = global.Object;
const hasOwn = v8.uncurryThis(Object.prototype.hasOwnProperty);
const Function = global.Function;
const call = v8.uncurryThis(Function.prototype.call);
const apply = v8.uncurryThis(Function.prototype.apply);
const Promise = global.Promise;
const Promise_resolve = v8.simpleBind(Promise.resolve, Promise);
binding.testExtraCanUseUtils = function() {
const fulfilledPromise = v8.createPromise();
v8.resolvePromise(
fulfilledPromise,
hasOwn({ test: 'test' }, 'test') ? 1 : -1
);
const fulfilledPromise2 = Promise_resolve(call(function (arg1) {
return (this.prop === arg1 && arg1 === 'value') ? 2 : -1;
}, { prop: 'value' }, 'value'));
const rejectedPromise = v8.createPromise();
v8.rejectPromise(rejectedPromise, apply(function (arg1, arg2) {
return (arg1 === arg2 && arg2 === 'x') ? 3 : -1;
}, null, new v8.InternalPackedArray('x', 'x')));
return {
privateSymbol: v8.createPrivateSymbol('sym'),
fulfilledPromise, // should be fulfilled with 1
fulfilledPromise2, // should be fulfilled with 2
rejectedPromise // should be rejected with 3
};
};
})
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