Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/runtime.cc

Issue 8199004: Reimplement Function.prototype.bind. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed review comments Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/runtime.h ('k') | src/runtime.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 1912 matching lines...) Expand 10 before | Expand all | Expand 10 after
1923 1923
1924 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) { 1924 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1925 NoHandleAllocation ha; 1925 NoHandleAllocation ha;
1926 ASSERT(args.length() == 1); 1926 ASSERT(args.length() == 1);
1927 CONVERT_CHECKED(JSFunction, f, args[0]); 1927 CONVERT_CHECKED(JSFunction, f, args[0]);
1928 f->shared()->set_name_should_print_as_anonymous(true); 1928 f->shared()->set_name_should_print_as_anonymous(true);
1929 return isolate->heap()->undefined_value(); 1929 return isolate->heap()->undefined_value();
1930 } 1930 }
1931 1931
1932 1932
1933 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1934 HandleScope scope(isolate);
1935 ASSERT(args.length() == 1);
1936
1937 CONVERT_CHECKED(JSFunction, fun, args[0]);
1938 fun->shared()->set_bound(true);
1939 return isolate->heap()->undefined_value();
1940 }
1941
1942 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) { 1933 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
1943 NoHandleAllocation ha; 1934 NoHandleAllocation ha;
1944 ASSERT(args.length() == 1); 1935 ASSERT(args.length() == 1);
1945 1936
1946 CONVERT_CHECKED(JSFunction, f, args[0]); 1937 CONVERT_CHECKED(JSFunction, f, args[0]);
1947 Object* obj = f->RemovePrototype(); 1938 Object* obj = f->RemovePrototype();
1948 if (obj->IsFailure()) return obj; 1939 if (obj->IsFailure()) return obj;
1949 1940
1950 return isolate->heap()->undefined_value(); 1941 return isolate->heap()->undefined_value();
1951 } 1942 }
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
2010 NoHandleAllocation ha; 2001 NoHandleAllocation ha;
2011 ASSERT(args.length() == 2); 2002 ASSERT(args.length() == 2);
2012 2003
2013 CONVERT_CHECKED(JSFunction, fun, args[0]); 2004 CONVERT_CHECKED(JSFunction, fun, args[0]);
2014 CONVERT_CHECKED(Smi, length, args[1]); 2005 CONVERT_CHECKED(Smi, length, args[1]);
2015 fun->shared()->set_length(length->value()); 2006 fun->shared()->set_length(length->value());
2016 return length; 2007 return length;
2017 } 2008 }
2018 2009
2019 2010
2020 // Creates a local, readonly, property called length with the correct
2021 // length (when read by the user). This effectively overwrites the
2022 // interceptor used to normally provide the length.
2023 RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2024 NoHandleAllocation ha;
2025 ASSERT(args.length() == 2);
2026 CONVERT_CHECKED(JSFunction, fun, args[0]);
2027 CONVERT_CHECKED(Smi, length, args[1]);
2028 MaybeObject* maybe_name =
2029 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2030 String* name;
2031 if (!maybe_name->To(&name)) return maybe_name;
2032 PropertyAttributes attr =
2033 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2034 return fun->AddProperty(name, length, attr, kNonStrictMode);
2035 }
2036
2037
2038 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) { 2011 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
2039 NoHandleAllocation ha; 2012 NoHandleAllocation ha;
2040 ASSERT(args.length() == 2); 2013 ASSERT(args.length() == 2);
2041 2014
2042 CONVERT_CHECKED(JSFunction, fun, args[0]); 2015 CONVERT_CHECKED(JSFunction, fun, args[0]);
2043 ASSERT(fun->should_have_prototype()); 2016 ASSERT(fun->should_have_prototype());
2044 Object* obj; 2017 Object* obj;
2045 { MaybeObject* maybe_obj = 2018 { MaybeObject* maybe_obj =
2046 Accessors::FunctionSetPrototype(fun, args[1], NULL); 2019 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2047 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2020 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
(...skipping 5871 matching lines...) Expand 10 before | Expand all | Expand 10 after
7919 // directly to properties. 7892 // directly to properties.
7920 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED; 7893 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
7921 Handle<JSFunction> result = 7894 Handle<JSFunction> result =
7922 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, 7895 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7923 context, 7896 context,
7924 pretenure_flag); 7897 pretenure_flag);
7925 return *result; 7898 return *result;
7926 } 7899 }
7927 7900
7928 7901
7929 static SmartArrayPointer<Handle<Object> > GetNonBoundArguments( 7902 // Find the arguments of the JavaScript function invocation that called
7930 int bound_argc, 7903 // into C++ code. Collect these in a newly allocated array of handles (possibly
7904 // prefixed by a number of empty handles).
7905 static SmartArrayPointer<Handle<Object> > GetCallerArguments(
7906 int prefix_argc,
7931 int* total_argc) { 7907 int* total_argc) {
7932 // Find frame containing arguments passed to the caller. 7908 // Find frame containing arguments passed to the caller.
7933 JavaScriptFrameIterator it; 7909 JavaScriptFrameIterator it;
7934 JavaScriptFrame* frame = it.frame(); 7910 JavaScriptFrame* frame = it.frame();
7935 List<JSFunction*> functions(2); 7911 List<JSFunction*> functions(2);
7936 frame->GetFunctions(&functions); 7912 frame->GetFunctions(&functions);
7937 if (functions.length() > 1) { 7913 if (functions.length() > 1) {
7938 int inlined_frame_index = functions.length() - 1; 7914 int inlined_frame_index = functions.length() - 1;
7939 JSFunction* inlined_function = functions[inlined_frame_index]; 7915 JSFunction* inlined_function = functions[inlined_frame_index];
7940 int args_count = inlined_function->shared()->formal_parameter_count(); 7916 int args_count = inlined_function->shared()->formal_parameter_count();
7941 ScopedVector<SlotRef> args_slots(args_count); 7917 ScopedVector<SlotRef> args_slots(args_count);
7942 SlotRef::ComputeSlotMappingForArguments(frame, 7918 SlotRef::ComputeSlotMappingForArguments(frame,
7943 inlined_frame_index, 7919 inlined_frame_index,
7944 &args_slots); 7920 &args_slots);
7945 7921
7946 *total_argc = bound_argc + args_count; 7922 *total_argc = prefix_argc + args_count;
7947 SmartArrayPointer<Handle<Object> > param_data( 7923 SmartArrayPointer<Handle<Object> > param_data(
7948 NewArray<Handle<Object> >(*total_argc)); 7924 NewArray<Handle<Object> >(*total_argc));
7949 for (int i = 0; i < args_count; i++) { 7925 for (int i = 0; i < args_count; i++) {
7950 Handle<Object> val = args_slots[i].GetValue(); 7926 Handle<Object> val = args_slots[i].GetValue();
7951 param_data[bound_argc + i] = val; 7927 param_data[prefix_argc + i] = val;
7952 } 7928 }
7953 return param_data; 7929 return param_data;
7954 } else { 7930 } else {
7955 it.AdvanceToArgumentsFrame(); 7931 it.AdvanceToArgumentsFrame();
7956 frame = it.frame(); 7932 frame = it.frame();
7957 int args_count = frame->ComputeParametersCount(); 7933 int args_count = frame->ComputeParametersCount();
7958 7934
7959 *total_argc = bound_argc + args_count; 7935 *total_argc = prefix_argc + args_count;
7960 SmartArrayPointer<Handle<Object> > param_data( 7936 SmartArrayPointer<Handle<Object> > param_data(
7961 NewArray<Handle<Object> >(*total_argc)); 7937 NewArray<Handle<Object> >(*total_argc));
7962 for (int i = 0; i < args_count; i++) { 7938 for (int i = 0; i < args_count; i++) {
7963 Handle<Object> val = Handle<Object>(frame->GetParameter(i)); 7939 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7964 param_data[bound_argc + i] = val; 7940 param_data[prefix_argc + i] = val;
7965 } 7941 }
7966 return param_data; 7942 return param_data;
7967 } 7943 }
7968 } 7944 }
7969 7945
7970 7946
7947 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7948 HandleScope scope(isolate);
7949 ASSERT(args.length() == 4);
7950 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
7951 RUNTIME_ASSERT(args[3]->IsNumber());
7952 Handle<Object> bindee = args.at<Object>(1);
7953
7954 // TODO(lrn): Create bound function in C++ code from premade shared info.
7955 bound_function->shared()->set_bound(true);
7956 // Get all arguments of calling function (Function.prototype.bind).
7957 int argc = 0;
7958 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
7959 // Don't count the this-arg.
7960 if (argc > 0) {
7961 ASSERT(*arguments[0] == args[2]);
7962 argc--;
7963 } else {
7964 ASSERT(args[2]->IsUndefined());
7965 }
7966 // Initialize array of bindings (function, this, and any existing arguments
7967 // if the function was already bound).
7968 Handle<FixedArray> new_bindings;
7969 int i;
7970 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7971 Handle<FixedArray> old_bindings(
7972 JSFunction::cast(*bindee)->function_bindings());
7973 new_bindings =
7974 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
7975 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
7976 i = 0;
7977 for (int n = old_bindings->length(); i < n; i++) {
7978 new_bindings->set(i, old_bindings->get(i));
7979 }
7980 } else {
7981 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7982 new_bindings = isolate->factory()->NewFixedArray(array_size);
7983 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7984 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7985 i = 2;
7986 }
7987 // Copy arguments, skipping the first which is "this_arg".
7988 for (int j = 0; j < argc; j++, i++) {
7989 new_bindings->set(i, *arguments[j + 1]);
7990 }
7991 new_bindings->set_map(isolate->heap()->fixed_cow_array_map());
7992 bound_function->set_function_bindings(*new_bindings);
7993
7994 // Update length.
7995 Handle<String> length_symbol = isolate->factory()->length_symbol();
7996 Handle<Object> new_length(args.at<Object>(3));
7997 PropertyAttributes attr =
7998 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
7999 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8000 return *bound_function;
8001 }
8002
8003
8004 RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8005 HandleScope handles(isolate);
8006 ASSERT(args.length() == 1);
8007 CONVERT_ARG_CHECKED(JSObject, callable, 0);
8008 if (callable->IsJSFunction()) {
8009 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8010 if (function->shared()->bound()) {
8011 Handle<FixedArray> bindings(function->function_bindings());
8012 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8013 return *isolate->factory()->NewJSArrayWithElements(bindings);
8014 }
8015 }
8016 return isolate->heap()->undefined_value();
8017 }
8018
8019
7971 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) { 8020 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
7972 HandleScope scope(isolate); 8021 HandleScope scope(isolate);
7973 ASSERT(args.length() == 2); 8022 ASSERT(args.length() == 1);
7974 // First argument is a function to use as a constructor. 8023 // First argument is a function to use as a constructor.
7975 CONVERT_ARG_CHECKED(JSFunction, function, 0); 8024 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8025 RUNTIME_ASSERT(function->shared()->bound());
7976 8026
7977 // Second argument is either null or an array of bound arguments. 8027 // The argument is a bound function. Extract its bound arguments
7978 Handle<FixedArray> bound_args; 8028 // and callable.
7979 int bound_argc = 0; 8029 Handle<FixedArray> bound_args =
7980 if (!args[1]->IsNull()) { 8030 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7981 CONVERT_ARG_CHECKED(JSArray, params, 1); 8031 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7982 RUNTIME_ASSERT(params->HasFastTypeElements()); 8032 Handle<Object> bound_function(
7983 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements())); 8033 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
7984 bound_argc = Smi::cast(params->length())->value(); 8034 ASSERT(!bound_function->IsJSFunction() ||
7985 } 8035 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
7986 8036
7987 int total_argc = 0; 8037 int total_argc = 0;
7988 SmartArrayPointer<Handle<Object> > param_data = 8038 SmartArrayPointer<Handle<Object> > param_data =
7989 GetNonBoundArguments(bound_argc, &total_argc); 8039 GetCallerArguments(bound_argc, &total_argc);
7990 for (int i = 0; i < bound_argc; i++) { 8040 for (int i = 0; i < bound_argc; i++) {
7991 Handle<Object> val = Handle<Object>(bound_args->get(i)); 8041 param_data[i] = Handle<Object>(bound_args->get(
7992 param_data[i] = val; 8042 JSFunction::kBoundArgumentsStartIndex + i));
7993 } 8043 }
7994 8044
8045 if (!bound_function->IsJSFunction()) {
8046 bool exception_thrown;
8047 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8048 &exception_thrown);
8049 if (exception_thrown) return Failure::Exception();
8050 }
8051 ASSERT(bound_function->IsJSFunction());
8052
7995 bool exception = false; 8053 bool exception = false;
7996 Handle<Object> result = 8054 Handle<Object> result =
7997 Execution::New(function, total_argc, *param_data, &exception); 8055 Execution::New(Handle<JSFunction>::cast(bound_function),
8056 total_argc, *param_data, &exception);
7998 if (exception) { 8057 if (exception) {
7999 return Failure::Exception(); 8058 return Failure::Exception();
8000 } 8059 }
8001
8002 ASSERT(!result.is_null()); 8060 ASSERT(!result.is_null());
8003 return *result; 8061 return *result;
8004 } 8062 }
8005 8063
8006 8064
8007 static void TrySettingInlineConstructStub(Isolate* isolate, 8065 static void TrySettingInlineConstructStub(Isolate* isolate,
8008 Handle<JSFunction> function) { 8066 Handle<JSFunction> function) {
8009 Handle<Object> prototype = isolate->factory()->null_value(); 8067 Handle<Object> prototype = isolate->factory()->null_value();
8010 if (function->has_instance_prototype()) { 8068 if (function->has_instance_prototype()) {
8011 prototype = Handle<Object>(function->instance_prototype(), isolate); 8069 prototype = Handle<Object>(function->instance_prototype(), isolate);
(...skipping 5276 matching lines...) Expand 10 before | Expand all | Expand 10 after
13288 } else { 13346 } else {
13289 // Handle last resort GC and make sure to allow future allocations 13347 // Handle last resort GC and make sure to allow future allocations
13290 // to grow the heap without causing GCs (if possible). 13348 // to grow the heap without causing GCs (if possible).
13291 isolate->counters()->gc_last_resort_from_js()->Increment(); 13349 isolate->counters()->gc_last_resort_from_js()->Increment();
13292 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags); 13350 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
13293 } 13351 }
13294 } 13352 }
13295 13353
13296 13354
13297 } } // namespace v8::internal 13355 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/runtime.h ('k') | src/runtime.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698