| Index: src/runtime/runtime-function.cc
|
| diff --git a/src/runtime/runtime-function.cc b/src/runtime/runtime-function.cc
|
| index 24ed128f670a039c635e4b39a7277d5e50a33ca5..9ec4cda81a11f4f2cfab49c28d7a8804599d75ea 100644
|
| --- a/src/runtime/runtime-function.cc
|
| +++ b/src/runtime/runtime-function.cc
|
| @@ -53,23 +53,23 @@
|
|
|
| RUNTIME_FUNCTION(Runtime_FunctionGetScript) {
|
| HandleScope scope(isolate);
|
| - DCHECK_EQ(1, args.length());
|
| - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0);
|
| -
|
| - if (function->IsJSBoundFunction()) return isolate->heap()->undefined_value();
|
| - Handle<Object> script(Handle<JSFunction>::cast(function)->shared()->script(),
|
| - isolate);
|
| + DCHECK(args.length() == 1);
|
| +
|
| + CONVERT_ARG_CHECKED(JSFunction, fun, 0);
|
| + Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
|
| if (!script->IsScript()) return isolate->heap()->undefined_value();
|
| +
|
| return *Script::GetWrapper(Handle<Script>::cast(script));
|
| }
|
|
|
|
|
| RUNTIME_FUNCTION(Runtime_FunctionGetSourceCode) {
|
| HandleScope scope(isolate);
|
| - DCHECK_EQ(1, args.length());
|
| - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0);
|
| - if (function->IsJSBoundFunction()) return isolate->heap()->undefined_value();
|
| - return *Handle<JSFunction>::cast(function)->shared()->GetSourceCode();
|
| + DCHECK(args.length() == 1);
|
| +
|
| + CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
|
| + Handle<SharedFunctionInfo> shared(f->shared());
|
| + return *shared->GetSourceCode();
|
| }
|
|
|
|
|
| @@ -152,6 +152,7 @@
|
|
|
| Handle<SharedFunctionInfo> target_shared(target->shared());
|
| Handle<SharedFunctionInfo> source_shared(source->shared());
|
| + RUNTIME_ASSERT(!source_shared->bound());
|
|
|
| if (!Compiler::Compile(source, KEEP_EXCEPTION)) {
|
| return isolate->heap()->exception();
|
| @@ -308,6 +309,137 @@
|
| }
|
|
|
|
|
| +RUNTIME_FUNCTION(Runtime_FunctionBindArguments) {
|
| + HandleScope scope(isolate);
|
| + DCHECK(args.length() == 5);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, bindee, 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, this_object, 2);
|
| + CONVERT_NUMBER_ARG_HANDLE_CHECKED(new_length, 3);
|
| + CONVERT_ARG_HANDLE_CHECKED(Object, proto, 4);
|
| +
|
| + // TODO(lrn): Create bound function in C++ code from premade shared info.
|
| + bound_function->shared()->set_bound(true);
|
| + bound_function->shared()->set_optimized_code_map(
|
| + isolate->heap()->cleared_optimized_code_map());
|
| + bound_function->shared()->set_inferred_name(isolate->heap()->empty_string());
|
| + bound_function->shared()->set_construct_stub(
|
| + *isolate->builtins()->JSBuiltinsConstructStub());
|
| + // Get all arguments of calling function (Function.prototype.bind).
|
| + int argc = 0;
|
| + base::SmartArrayPointer<Handle<Object>> arguments =
|
| + Runtime::GetCallerArguments(isolate, 0, &argc);
|
| + // Don't count the this-arg.
|
| + if (argc > 0) {
|
| + RUNTIME_ASSERT(arguments[0].is_identical_to(this_object));
|
| + argc--;
|
| + } else {
|
| + RUNTIME_ASSERT(this_object->IsUndefined());
|
| + }
|
| + // Initialize array of bindings (function, this, and any existing arguments
|
| + // if the function was already bound).
|
| + Handle<BindingsArray> new_bindings;
|
| + int out_index = 0;
|
| + Handle<TypeFeedbackVector> vector(
|
| + bound_function->shared()->feedback_vector());
|
| + if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
|
| + Handle<BindingsArray> old_bindings(
|
| + JSFunction::cast(*bindee)->function_bindings());
|
| + RUNTIME_ASSERT(old_bindings->bindings_count() >= 0);
|
| + bindee = handle(old_bindings->bound_function(), isolate);
|
| + Handle<Object> old_bound_this(old_bindings->bound_this(), isolate);
|
| + new_bindings = BindingsArray::New(isolate, vector, bindee, old_bound_this,
|
| + old_bindings->bindings_count() + argc);
|
| + for (int n = old_bindings->bindings_count(); out_index < n; out_index++) {
|
| + new_bindings->set_binding(out_index, old_bindings->binding(out_index));
|
| + }
|
| + } else {
|
| + new_bindings =
|
| + BindingsArray::New(isolate, vector, bindee, this_object, argc);
|
| + }
|
| + // Copy arguments, skipping the first which is "this_arg".
|
| + for (int j = 0; j < argc; j++, out_index++) {
|
| + new_bindings->set_binding(out_index, *arguments[j + 1]);
|
| + }
|
| + new_bindings->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
|
| + bound_function->set_function_bindings(*new_bindings);
|
| +
|
| + // Update length. Have to remove the prototype first so that map migration
|
| + // is happy about the number of fields.
|
| + RUNTIME_ASSERT(bound_function->RemovePrototype());
|
| +
|
| + // The new function should have the given prototype.
|
| + Handle<Map> bound_function_map =
|
| + bindee->IsConstructor()
|
| + ? isolate->bound_function_with_constructor_map()
|
| + : isolate->bound_function_without_constructor_map();
|
| + if (bound_function_map->prototype() != *proto) {
|
| + bound_function_map = Map::TransitionToPrototype(bound_function_map, proto,
|
| + REGULAR_PROTOTYPE);
|
| + }
|
| + JSObject::MigrateToMap(bound_function, bound_function_map);
|
| + DCHECK_EQ(bindee->IsConstructor(), bound_function->IsConstructor());
|
| +
|
| + Handle<String> length_string = isolate->factory()->length_string();
|
| + // These attributes must be kept in sync with how the bootstrapper
|
| + // configures the bound_function_map retrieved above.
|
| + // We use ...IgnoreAttributes() here because of length's read-onliness.
|
| + PropertyAttributes attr =
|
| + static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
|
| + RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, JSObject::SetOwnPropertyIgnoreAttributes(
|
| + bound_function, length_string, new_length, attr));
|
| + return *bound_function;
|
| +}
|
| +
|
| +
|
| +RUNTIME_FUNCTION(Runtime_BoundFunctionGetBindings) {
|
| + HandleScope handles(isolate);
|
| + DCHECK(args.length() == 1);
|
| + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
|
| + if (callable->IsJSFunction()) {
|
| + Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
|
| + if (function->shared()->bound()) {
|
| + RUNTIME_ASSERT(function->function_bindings()->IsBindingsArray());
|
| + Handle<BindingsArray> bindings(function->function_bindings());
|
| + return *BindingsArray::CreateRuntimeBindings(bindings);
|
| + }
|
| + }
|
| + return isolate->heap()->undefined_value();
|
| +}
|
| +
|
| +
|
| +RUNTIME_FUNCTION(Runtime_NewObjectFromBound) {
|
| + HandleScope scope(isolate);
|
| + DCHECK(args.length() == 1);
|
| + // First argument is a function to use as a constructor.
|
| + CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
|
| + RUNTIME_ASSERT(function->shared()->bound());
|
| +
|
| + // The argument is a bound function. Extract its bound arguments
|
| + // and callable.
|
| + Handle<BindingsArray> bound_args =
|
| + handle(BindingsArray::cast(function->function_bindings()));
|
| + int bound_argc = bound_args->bindings_count();
|
| + Handle<Object> bound_function(bound_args->bound_function(), isolate);
|
| + DCHECK(!bound_function->IsJSFunction() ||
|
| + !Handle<JSFunction>::cast(bound_function)->shared()->bound());
|
| +
|
| + int total_argc = 0;
|
| + base::SmartArrayPointer<Handle<Object>> param_data =
|
| + Runtime::GetCallerArguments(isolate, bound_argc, &total_argc);
|
| + for (int i = 0; i < bound_argc; i++) {
|
| + param_data[i] = handle(bound_args->binding(i), isolate);
|
| + }
|
| +
|
| + Handle<Object> result;
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
| + isolate, result, Execution::New(isolate, bound_function, bound_function,
|
| + total_argc, param_data.get()));
|
| + return *result;
|
| +}
|
| +
|
| +
|
| RUNTIME_FUNCTION(Runtime_Call) {
|
| HandleScope scope(isolate);
|
| DCHECK_LE(2, args.length());
|
| @@ -395,9 +527,9 @@
|
|
|
| RUNTIME_FUNCTION(Runtime_IsFunction) {
|
| SealHandleScope shs(isolate);
|
| - DCHECK_EQ(1, args.length());
|
| - CONVERT_ARG_CHECKED(Object, object, 0);
|
| - return isolate->heap()->ToBoolean(object->IsFunction());
|
| + DCHECK(args.length() == 1);
|
| + CONVERT_ARG_CHECKED(Object, obj, 0);
|
| + return isolate->heap()->ToBoolean(obj->IsJSFunction());
|
| }
|
|
|
|
|
| @@ -412,11 +544,8 @@
|
| RUNTIME_FUNCTION(Runtime_FunctionToString) {
|
| HandleScope scope(isolate);
|
| DCHECK_EQ(1, args.length());
|
| - CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0);
|
| - return function->IsJSBoundFunction()
|
| - ? *JSBoundFunction::ToString(
|
| - Handle<JSBoundFunction>::cast(function))
|
| - : *JSFunction::ToString(Handle<JSFunction>::cast(function));
|
| + CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
|
| + return *JSFunction::ToString(function);
|
| }
|
|
|
| } // namespace internal
|
|
|