Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index e0f507e1774bbd7c7d500994f40a07e74ae8f1e6..e614103b4d4a8695666e6f78e470703ac0454f31 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -1930,15 +1930,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) { |
} |
-RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) { |
- HandleScope scope(isolate); |
- ASSERT(args.length() == 1); |
- |
- CONVERT_CHECKED(JSFunction, fun, args[0]); |
- fun->shared()->set_bound(true); |
- return isolate->heap()->undefined_value(); |
-} |
- |
RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) { |
NoHandleAllocation ha; |
ASSERT(args.length() == 1); |
@@ -2017,24 +2008,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) { |
} |
-// Creates a local, readonly, property called length with the correct |
-// length (when read by the user). This effectively overwrites the |
-// interceptor used to normally provide the length. |
-RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) { |
- NoHandleAllocation ha; |
- ASSERT(args.length() == 2); |
- CONVERT_CHECKED(JSFunction, fun, args[0]); |
- CONVERT_CHECKED(Smi, length, args[1]); |
- MaybeObject* maybe_name = |
- isolate->heap()->AllocateStringFromAscii(CStrVector("length")); |
- String* name; |
- if (!maybe_name->To(&name)) return maybe_name; |
- PropertyAttributes attr = |
- static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY); |
- return fun->AddProperty(name, length, attr, kNonStrictMode); |
-} |
- |
- |
RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) { |
NoHandleAllocation ha; |
ASSERT(args.length() == 2); |
@@ -7926,8 +7899,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) { |
} |
-static SmartArrayPointer<Handle<Object> > GetNonBoundArguments( |
- int bound_argc, |
+// Find the arguments of the JavaScript function invocation that called |
+// into C++ code. Collect these in a newly allocated array of handles (possibly |
+// prefixed by a number of empty handles). |
+static SmartArrayPointer<Handle<Object> > GetCallerArguments( |
+ int prefix_argc, |
int* total_argc) { |
// Find frame containing arguments passed to the caller. |
JavaScriptFrameIterator it; |
@@ -7943,12 +7919,12 @@ static SmartArrayPointer<Handle<Object> > GetNonBoundArguments( |
inlined_frame_index, |
&args_slots); |
- *total_argc = bound_argc + args_count; |
+ *total_argc = prefix_argc + args_count; |
SmartArrayPointer<Handle<Object> > param_data( |
NewArray<Handle<Object> >(*total_argc)); |
for (int i = 0; i < args_count; i++) { |
Handle<Object> val = args_slots[i].GetValue(); |
- param_data[bound_argc + i] = val; |
+ param_data[prefix_argc + i] = val; |
} |
return param_data; |
} else { |
@@ -7956,49 +7932,131 @@ static SmartArrayPointer<Handle<Object> > GetNonBoundArguments( |
frame = it.frame(); |
int args_count = frame->ComputeParametersCount(); |
- *total_argc = bound_argc + args_count; |
+ *total_argc = prefix_argc + args_count; |
SmartArrayPointer<Handle<Object> > param_data( |
NewArray<Handle<Object> >(*total_argc)); |
for (int i = 0; i < args_count; i++) { |
Handle<Object> val = Handle<Object>(frame->GetParameter(i)); |
- param_data[bound_argc + i] = val; |
+ param_data[prefix_argc + i] = val; |
} |
return param_data; |
} |
} |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 4); |
+ CONVERT_ARG_CHECKED(JSFunction, bound_function, 0); |
+ RUNTIME_ASSERT(args[3]->IsNumber()); |
+ Handle<Object> bindee = args.at<Object>(1); |
+ |
+ // TODO(lrn): Create bound function in C++ code from premade shared info. |
+ bound_function->shared()->set_bound(true); |
+ // Get all arguments of calling function (Function.prototype.bind). |
+ int argc = 0; |
+ SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc); |
+ // Don't count the this-arg. |
+ if (argc > 0) { |
+ ASSERT(*arguments[0] == args[2]); |
+ argc--; |
+ } else { |
+ ASSERT(args[2]->IsUndefined()); |
+ } |
+ // Initialize array of bindings (function, this, and any existing arguments |
+ // if the function was already bound). |
+ Handle<FixedArray> new_bindings; |
+ int i; |
+ if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) { |
+ Handle<FixedArray> old_bindings( |
+ JSFunction::cast(*bindee)->function_bindings()); |
+ new_bindings = |
+ isolate->factory()->NewFixedArray(old_bindings->length() + argc); |
+ bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex)); |
+ i = 0; |
+ for (int n = old_bindings->length(); i < n; i++) { |
+ new_bindings->set(i, old_bindings->get(i)); |
+ } |
+ } else { |
+ 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]); |
+ i = 2; |
+ } |
+ // Copy arguments, skipping the first which is "this_arg". |
+ for (int j = 0; j < argc; j++, i++) { |
+ new_bindings->set(i, *arguments[j + 1]); |
+ } |
+ new_bindings->set_map(isolate->heap()->fixed_cow_array_map()); |
+ bound_function->set_function_bindings(*new_bindings); |
+ |
+ // Update length. |
+ Handle<String> length_symbol = isolate->factory()->length_symbol(); |
+ Handle<Object> new_length(args.at<Object>(3)); |
+ PropertyAttributes attr = |
+ static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY); |
+ ForceSetProperty(bound_function, length_symbol, new_length, attr); |
+ return *bound_function; |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) { |
+ HandleScope handles(isolate); |
+ ASSERT(args.length() == 1); |
+ CONVERT_ARG_CHECKED(JSObject, callable, 0); |
+ if (callable->IsJSFunction()) { |
+ Handle<JSFunction> function = Handle<JSFunction>::cast(callable); |
+ if (function->shared()->bound()) { |
+ Handle<FixedArray> bindings(function->function_bindings()); |
+ ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map()); |
+ return *isolate->factory()->NewJSArrayWithElements(bindings); |
+ } |
+ } |
+ return isolate->heap()->undefined_value(); |
+} |
+ |
+ |
RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) { |
HandleScope scope(isolate); |
- ASSERT(args.length() == 2); |
+ ASSERT(args.length() == 1); |
// First argument is a function to use as a constructor. |
CONVERT_ARG_CHECKED(JSFunction, function, 0); |
- |
- // Second argument is either null or an array of bound arguments. |
- Handle<FixedArray> bound_args; |
- int bound_argc = 0; |
- if (!args[1]->IsNull()) { |
- CONVERT_ARG_CHECKED(JSArray, params, 1); |
- RUNTIME_ASSERT(params->HasFastTypeElements()); |
- bound_args = Handle<FixedArray>(FixedArray::cast(params->elements())); |
- bound_argc = Smi::cast(params->length())->value(); |
- } |
+ RUNTIME_ASSERT(function->shared()->bound()); |
+ |
+ // The argument is a bound function. Extract its bound arguments |
+ // and callable. |
+ Handle<FixedArray> bound_args = |
+ Handle<FixedArray>(FixedArray::cast(function->function_bindings())); |
+ int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex; |
+ Handle<Object> bound_function( |
+ JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex))); |
+ ASSERT(!bound_function->IsJSFunction() || |
+ !Handle<JSFunction>::cast(bound_function)->shared()->bound()); |
int total_argc = 0; |
SmartArrayPointer<Handle<Object> > param_data = |
- GetNonBoundArguments(bound_argc, &total_argc); |
+ GetCallerArguments(bound_argc, &total_argc); |
for (int i = 0; i < bound_argc; i++) { |
- Handle<Object> val = Handle<Object>(bound_args->get(i)); |
- param_data[i] = val; |
+ param_data[i] = Handle<Object>(bound_args->get( |
+ JSFunction::kBoundArgumentsStartIndex + i)); |
+ } |
+ |
+ if (!bound_function->IsJSFunction()) { |
+ bool exception_thrown; |
+ bound_function = Execution::TryGetConstructorDelegate(bound_function, |
+ &exception_thrown); |
+ if (exception_thrown) return Failure::Exception(); |
} |
+ ASSERT(bound_function->IsJSFunction()); |
bool exception = false; |
Handle<Object> result = |
- Execution::New(function, total_argc, *param_data, &exception); |
+ Execution::New(Handle<JSFunction>::cast(bound_function), |
+ total_argc, *param_data, &exception); |
if (exception) { |
- return Failure::Exception(); |
+ return Failure::Exception(); |
} |
- |
ASSERT(!result.is_null()); |
return *result; |
} |