Revision: 21839
Author: [email protected]
Date: Fri Jun 13 12:19:04 2014 UTC
Log: Have one, long-lived map for bound functions.
This avoids creating a new map for every bound function. Bonus: some
cleanup in Runtime_FunctionBindArguments.
[email protected]
Review URL: https://codereview.chromium.org/335653002
http://code.google.com/p/v8/source/detail?r=21839
Added:
/branches/bleeding_edge/test/mjsunit/runtime-gen/functionbindarguments.js
Modified:
/branches/bleeding_edge/include/v8.h
/branches/bleeding_edge/src/bootstrapper.cc
/branches/bleeding_edge/src/contexts.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/v8natives.js
/branches/bleeding_edge/tools/generate-runtime-tests.py
=======================================
--- /dev/null
+++
/branches/bleeding_edge/test/mjsunit/runtime-gen/functionbindarguments.js
Fri Jun 13 12:19:04 2014 UTC
@@ -0,0 +1,8 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _bound_function = function() {};
+var _bindee = new Object();
+var arg2 = undefined;
+var _new_length = 1.5;
+%FunctionBindArguments(_bound_function, _bindee, arg2, _new_length);
=======================================
--- /branches/bleeding_edge/include/v8.h Fri Jun 13 11:06:42 2014 UTC
+++ /branches/bleeding_edge/include/v8.h Fri Jun 13 12:19:04 2014 UTC
@@ -5525,7 +5525,7 @@
static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
static const int kFixedArrayHeaderSize = 2 * kApiPointerSize;
static const int kContextHeaderSize = 2 * kApiPointerSize;
- static const int kContextEmbedderDataIndex = 75;
+ static const int kContextEmbedderDataIndex = 76;
static const int kFullStringRepresentationMask = 0x07;
static const int kStringEncodingMask = 0x4;
static const int kExternalTwoByteRepresentationTag = 0x02;
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Thu Jun 12 17:31:54 2014 UTC
+++ /branches/bleeding_edge/src/bootstrapper.cc Fri Jun 13 12:19:04 2014 UTC
@@ -262,24 +262,32 @@
void TransferNamedProperties(Handle<JSObject> from, Handle<JSObject> to);
void TransferIndexedProperties(Handle<JSObject> from, Handle<JSObject>
to);
- enum PrototypePropertyMode {
- DONT_ADD_PROTOTYPE,
- ADD_READONLY_PROTOTYPE,
- ADD_WRITEABLE_PROTOTYPE
+ enum FunctionMode {
+ // With prototype.
+ FUNCTION_WITH_WRITEABLE_PROTOTYPE,
+ FUNCTION_WITH_READONLY_PROTOTYPE,
+ // Without prototype.
+ FUNCTION_WITHOUT_PROTOTYPE,
+ BOUND_FUNCTION
};
- Handle<Map> CreateFunctionMap(PrototypePropertyMode prototype_mode);
+ static bool IsFunctionModeWithPrototype(FunctionMode function_mode) {
+ return (function_mode == FUNCTION_WITH_WRITEABLE_PROTOTYPE ||
+ function_mode == FUNCTION_WITH_READONLY_PROTOTYPE);
+ }
+
+ Handle<Map> CreateFunctionMap(FunctionMode function_mode);
void SetFunctionInstanceDescriptor(Handle<Map> map,
- PrototypePropertyMode prototypeMode);
+ FunctionMode function_mode);
void MakeFunctionInstancePrototypeWritable();
Handle<Map> CreateStrictFunctionMap(
- PrototypePropertyMode prototype_mode,
+ FunctionMode function_mode,
Handle<JSFunction> empty_function);
void SetStrictFunctionInstanceDescriptor(Handle<Map> map,
- PrototypePropertyMode
propertyMode);
+ FunctionMode function_mode);
static bool CompileBuiltin(Isolate* isolate, int index);
static bool CompileExperimentalBuiltin(Isolate* isolate, int index);
@@ -382,8 +390,8 @@
void Genesis::SetFunctionInstanceDescriptor(
- Handle<Map> map, PrototypePropertyMode prototypeMode) {
- int size = (prototypeMode == DONT_ADD_PROTOTYPE) ? 4 : 5;
+ Handle<Map> map, FunctionMode function_mode) {
+ int size = IsFunctionModeWithPrototype(function_mode) ? 5 : 4;
Map::EnsureDescriptorSlack(map, size);
PropertyAttributes attribs = static_cast<PropertyAttributes>(
@@ -417,8 +425,8 @@
caller, attribs);
map->AppendDescriptor(&d);
}
- if (prototypeMode != DONT_ADD_PROTOTYPE) {
- if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) {
+ if (IsFunctionModeWithPrototype(function_mode)) {
+ if (function_mode == FUNCTION_WITH_WRITEABLE_PROTOTYPE) {
attribs = static_cast<PropertyAttributes>(attribs & ~READ_ONLY);
}
Handle<AccessorInfo> prototype =
@@ -430,10 +438,10 @@
}
-Handle<Map> Genesis::CreateFunctionMap(PrototypePropertyMode
prototype_mode) {
+Handle<Map> Genesis::CreateFunctionMap(FunctionMode function_mode) {
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
- SetFunctionInstanceDescriptor(map, prototype_mode);
- map->set_function_with_prototype(prototype_mode != DONT_ADD_PROTOTYPE);
+ SetFunctionInstanceDescriptor(map, function_mode);
+
map->set_function_with_prototype(IsFunctionModeWithPrototype(function_mode));
return map;
}
@@ -445,14 +453,15 @@
// Functions with this map will not have a 'prototype' property, and
// can not be used as constructors.
Handle<Map> function_without_prototype_map =
- CreateFunctionMap(DONT_ADD_PROTOTYPE);
+ CreateFunctionMap(FUNCTION_WITHOUT_PROTOTYPE);
native_context()->set_sloppy_function_without_prototype_map(
*function_without_prototype_map);
// Allocate the function map. This map is temporary, used only for
processing
// of builtins.
// Later the map is replaced with writable prototype map, allocated
below.
- Handle<Map> function_map = CreateFunctionMap(ADD_READONLY_PROTOTYPE);
+ Handle<Map> function_map =
+ CreateFunctionMap(FUNCTION_WITH_READONLY_PROTOTYPE);
native_context()->set_sloppy_function_map(*function_map);
native_context()->set_sloppy_function_with_readonly_prototype_map(
*function_map);
@@ -460,7 +469,7 @@
// The final map for functions. Writeable prototype.
// This map is installed in MakeFunctionInstancePrototypeWritable.
sloppy_function_map_writable_prototype_ =
- CreateFunctionMap(ADD_WRITEABLE_PROTOTYPE);
+ CreateFunctionMap(FUNCTION_WITH_WRITEABLE_PROTOTYPE);
Factory* factory = isolate->factory();
@@ -514,7 +523,8 @@
sloppy_function_map_writable_prototype_->set_prototype(*empty_function);
// Allocate the function map first and then patch the prototype later
- Handle<Map> empty_function_map = CreateFunctionMap(DONT_ADD_PROTOTYPE);
+ Handle<Map> empty_function_map =
+ CreateFunctionMap(FUNCTION_WITHOUT_PROTOTYPE);
empty_function_map->set_prototype(
native_context()->object_function()->prototype());
empty_function->set_map(*empty_function_map);
@@ -523,8 +533,8 @@
void Genesis::SetStrictFunctionInstanceDescriptor(
- Handle<Map> map, PrototypePropertyMode prototypeMode) {
- int size = (prototypeMode == DONT_ADD_PROTOTYPE) ? 4 : 5;
+ Handle<Map> map, FunctionMode function_mode) {
+ int size = IsFunctionModeWithPrototype(function_mode) ? 5 : 4;
Map::EnsureDescriptorSlack(map, size);
Handle<AccessorPair> arguments(factory()->NewAccessorPair());
@@ -534,9 +544,17 @@
PropertyAttributes ro_attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
- Handle<AccessorInfo> length =
- Accessors::FunctionLengthInfo(isolate(), ro_attribs);
- { // Add length.
+ // Add length.
+ if (function_mode == BOUND_FUNCTION) {
+ Handle<String> length_string = isolate()->factory()->length_string();
+ FieldDescriptor d(length_string, 0, ro_attribs,
Representation::Tagged());
+ map->AppendDescriptor(&d);
+ } else {
+ ASSERT(function_mode == FUNCTION_WITH_WRITEABLE_PROTOTYPE ||
+ function_mode == FUNCTION_WITH_READONLY_PROTOTYPE ||
+ function_mode == FUNCTION_WITHOUT_PROTOTYPE);
+ Handle<AccessorInfo> length =
+ Accessors::FunctionLengthInfo(isolate(), ro_attribs);
CallbacksDescriptor d(Handle<Name>(Name::cast(length->name())),
length, ro_attribs);
map->AppendDescriptor(&d);
@@ -557,10 +575,11 @@
CallbacksDescriptor d(factory()->caller_string(), caller, rw_attribs);
map->AppendDescriptor(&d);
}
- if (prototypeMode != DONT_ADD_PROTOTYPE) {
+ if (IsFunctionModeWithPrototype(function_mode)) {
// Add prototype.
PropertyAttributes attribs =
- prototypeMode == ADD_WRITEABLE_PROTOTYPE ? rw_attribs : ro_attribs;
+ function_mode == FUNCTION_WITH_WRITEABLE_PROTOTYPE ? rw_attribs
+ : ro_attribs;
Handle<AccessorInfo> prototype =
Accessors::FunctionPrototypeInfo(isolate(), attribs);
CallbacksDescriptor d(Handle<Name>(Name::cast(prototype->name())),
@@ -605,11 +624,11 @@
Handle<Map> Genesis::CreateStrictFunctionMap(
- PrototypePropertyMode prototype_mode,
+ FunctionMode function_mode,
Handle<JSFunction> empty_function) {
Handle<Map> map = factory()->NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
- SetStrictFunctionInstanceDescriptor(map, prototype_mode);
- map->set_function_with_prototype(prototype_mode != DONT_ADD_PROTOTYPE);
+ SetStrictFunctionInstanceDescriptor(map, function_mode);
+
map->set_function_with_prototype(IsFunctionModeWithPrototype(function_mode));
map->set_prototype(*empty_function);
return map;
}
@@ -618,7 +637,7 @@
void Genesis::CreateStrictModeFunctionMaps(Handle<JSFunction> empty) {
// Allocate map for the prototype-less strict mode instances.
Handle<Map> strict_function_without_prototype_map =
- CreateStrictFunctionMap(DONT_ADD_PROTOTYPE, empty);
+ CreateStrictFunctionMap(FUNCTION_WITHOUT_PROTOTYPE, empty);
native_context()->set_strict_function_without_prototype_map(
*strict_function_without_prototype_map);
@@ -626,18 +645,23 @@
// only for processing of builtins.
// Later the map is replaced with writable prototype map, allocated
below.
Handle<Map> strict_function_map =
- CreateStrictFunctionMap(ADD_READONLY_PROTOTYPE, empty);
+ CreateStrictFunctionMap(FUNCTION_WITH_READONLY_PROTOTYPE, empty);
native_context()->set_strict_function_map(*strict_function_map);
// The final map for the strict mode functions. Writeable prototype.
// This map is installed in MakeFunctionInstancePrototypeWritable.
strict_function_map_writable_prototype_ =
- CreateStrictFunctionMap(ADD_WRITEABLE_PROTOTYPE, empty);
+ CreateStrictFunctionMap(FUNCTION_WITH_WRITEABLE_PROTOTYPE, empty);
+ // Special map for bound functions.
+ Handle<Map> bound_function_map =
+ CreateStrictFunctionMap(BOUND_FUNCTION, empty);
+ native_context()->set_bound_function_map(*bound_function_map);
// Complete the callbacks.
PoisonArgumentsAndCaller(strict_function_without_prototype_map);
PoisonArgumentsAndCaller(strict_function_map);
PoisonArgumentsAndCaller(strict_function_map_writable_prototype_);
+ PoisonArgumentsAndCaller(bound_function_map);
}
=======================================
--- /branches/bleeding_edge/src/contexts.h Thu Jun 12 17:31:54 2014 UTC
+++ /branches/bleeding_edge/src/contexts.h Fri Jun 13 12:19:04 2014 UTC
@@ -130,6 +130,7 @@
sloppy_function_without_prototype_map) \
V(STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, \
strict_function_without_prototype_map) \
+ V(BOUND_FUNCTION_MAP_INDEX, Map, bound_function_map) \
V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map)\
V(SLOPPY_ARGUMENTS_BOILERPLATE_INDEX, JSObject, \
sloppy_arguments_boilerplate) \
@@ -271,6 +272,7 @@
STRICT_FUNCTION_MAP_INDEX,
SLOPPY_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
+ BOUND_FUNCTION_MAP_INDEX,
INITIAL_OBJECT_PROTOTYPE_INDEX,
INITIAL_ARRAY_PROTOTYPE_INDEX,
BOOLEAN_FUNCTION_INDEX,
=======================================
--- /branches/bleeding_edge/src/runtime.cc Fri Jun 13 09:46:29 2014 UTC
+++ /branches/bleeding_edge/src/runtime.cc Fri Jun 13 12:19:04 2014 UTC
@@ -8192,8 +8192,9 @@
HandleScope scope(isolate);
ASSERT(args.length() == 4);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
- RUNTIME_ASSERT(args[3]->IsNumber());
- Handle<Object> bindee = args.at<Object>(1);
+ CONVERT_ARG_HANDLE_CHECKED(Object, bindee, 1);
+ CONVERT_ARG_HANDLE_CHECKED(Object, this_object, 2);
+ CONVERT_NUMBER_ARG_HANDLE_CHECKED(new_length, 3);
// TODO(lrn): Create bound function in C++ code from premade shared info.
bound_function->shared()->set_bound(true);
@@ -8203,10 +8204,10 @@
GetCallerArguments(isolate, 0, &argc);
// Don't count the this-arg.
if (argc > 0) {
- RUNTIME_ASSERT(*arguments[0] == args[2]);
+ RUNTIME_ASSERT(arguments[0].is_identical_to(this_object));
argc--;
} else {
- RUNTIME_ASSERT(args[2]->IsUndefined());
+ RUNTIME_ASSERT(this_object->IsUndefined());
}
// Initialize array of bindings (function, this, and any existing
arguments
// if the function was already bound).
@@ -8228,7 +8229,7 @@
int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
new_bindings = isolate->factory()->NewFixedArray(array_size);
new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
- new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
+ new_bindings->set(JSFunction::kBoundThisIndex, *this_object);
i = 2;
}
// Copy arguments, skipping the first which is "this_arg".
@@ -8239,13 +8240,17 @@
isolate->heap()->fixed_cow_array_map());
bound_function->set_function_bindings(*new_bindings);
- // Update length.
+ // Update length. Have to remove the prototype first so that map
migration
+ // is happy about the number of fields.
+ RUNTIME_ASSERT(bound_function->RemovePrototype());
+ Handle<Map> bound_function_map(
+ isolate->native_context()->bound_function_map());
+ JSObject::MigrateToMap(bound_function, bound_function_map);
Handle<String> length_string = isolate->factory()->length_string();
- Handle<Object> new_length(args.at<Object>(3));
PropertyAttributes attr =
static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
- Runtime::ForceSetObjectProperty(
- bound_function, length_string, new_length, attr).Assert();
+ JSObject::SetOwnPropertyIgnoreAttributes(bound_function, length_string,
+ new_length, attr);
return *bound_function;
}
=======================================
--- /branches/bleeding_edge/src/v8natives.js Thu Jun 12 08:28:19 2014 UTC
+++ /branches/bleeding_edge/src/v8natives.js Fri Jun 13 12:19:04 2014 UTC
@@ -1781,19 +1781,15 @@
return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
};
- %FunctionRemovePrototype(boundFunction);
var new_length = 0;
- if (%_ClassOf(this) == "Function") {
- // Function or FunctionProxy.
- var old_length = this.length;
- // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
- if ((typeof old_length === "number") &&
- ((old_length >>> 0) === old_length)) {
- var argc = %_ArgumentsLength();
- if (argc > 0) argc--; // Don't count the thisArg as parameter.
- new_length = old_length - argc;
- if (new_length < 0) new_length = 0;
- }
+ var old_length = this.length;
+ // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
+ if ((typeof old_length === "number") &&
+ ((old_length >>> 0) === old_length)) {
+ var argc = %_ArgumentsLength();
+ if (argc > 0) argc--; // Don't count the thisArg as parameter.
+ new_length = old_length - argc;
+ if (new_length < 0) new_length = 0;
}
// This runtime function finds any remaining arguments on the stack,
// so we don't pass the arguments object.
=======================================
--- /branches/bleeding_edge/tools/generate-runtime-tests.py Thu Jun 12
17:31:54 2014 UTC
+++ /branches/bleeding_edge/tools/generate-runtime-tests.py Fri Jun 13
12:19:04 2014 UTC
@@ -48,9 +48,9 @@
# remove or change runtime functions, but make sure we don't lose our
ability
# to parse them!
EXPECTED_FUNCTION_COUNT = 358
-EXPECTED_FUZZABLE_COUNT = 325
+EXPECTED_FUZZABLE_COUNT = 326
EXPECTED_CCTEST_COUNT = 6
-EXPECTED_UNKNOWN_COUNT = 5
+EXPECTED_UNKNOWN_COUNT = 4
EXPECTED_BUILTINS_COUNT = 798
@@ -143,6 +143,7 @@
"DateParseString": [None, "new Array(8)", None],
"DefineOrRedefineAccessorProperty": [None, None, "function() {}",
"function() {}", 2, None],
+ "FunctionBindArguments": [None, None, "undefined", None, None],
"GetBreakLocations": [None, 0, None],
"GetDefaultReceiver": ["function() {}", None],
"GetImplFromInitializedIntlObject": ["new Intl.NumberFormat('en-US')",
None],
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.