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

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: 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
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 1907 matching lines...) Expand 10 before | Expand all | Expand 10 after
1918 1918
1919 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) { 1919 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1920 NoHandleAllocation ha; 1920 NoHandleAllocation ha;
1921 ASSERT(args.length() == 1); 1921 ASSERT(args.length() == 1);
1922 CONVERT_CHECKED(JSFunction, f, args[0]); 1922 CONVERT_CHECKED(JSFunction, f, args[0]);
1923 f->shared()->set_name_should_print_as_anonymous(true); 1923 f->shared()->set_name_should_print_as_anonymous(true);
1924 return isolate->heap()->undefined_value(); 1924 return isolate->heap()->undefined_value();
1925 } 1925 }
1926 1926
1927 1927
1928 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1929 HandleScope scope(isolate);
1930 ASSERT(args.length() == 1);
1931
1932 CONVERT_CHECKED(JSFunction, fun, args[0]);
1933 fun->shared()->set_bound(true);
1934 return isolate->heap()->undefined_value();
1935 }
1936
1937 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) { 1928 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
1938 NoHandleAllocation ha; 1929 NoHandleAllocation ha;
1939 ASSERT(args.length() == 1); 1930 ASSERT(args.length() == 1);
1940 1931
1941 CONVERT_CHECKED(JSFunction, f, args[0]); 1932 CONVERT_CHECKED(JSFunction, f, args[0]);
1942 Object* obj = f->RemovePrototype(); 1933 Object* obj = f->RemovePrototype();
1943 if (obj->IsFailure()) return obj; 1934 if (obj->IsFailure()) return obj;
1944 1935
1945 return isolate->heap()->undefined_value(); 1936 return isolate->heap()->undefined_value();
1946 } 1937 }
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
2005 NoHandleAllocation ha; 1996 NoHandleAllocation ha;
2006 ASSERT(args.length() == 2); 1997 ASSERT(args.length() == 2);
2007 1998
2008 CONVERT_CHECKED(JSFunction, fun, args[0]); 1999 CONVERT_CHECKED(JSFunction, fun, args[0]);
2009 CONVERT_CHECKED(Smi, length, args[1]); 2000 CONVERT_CHECKED(Smi, length, args[1]);
2010 fun->shared()->set_length(length->value()); 2001 fun->shared()->set_length(length->value());
2011 return length; 2002 return length;
2012 } 2003 }
2013 2004
2014 2005
2015 // Creates a local, readonly, property called length with the correct
2016 // length (when read by the user). This effectively overwrites the
2017 // interceptor used to normally provide the length.
2018 RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2019 NoHandleAllocation ha;
2020 ASSERT(args.length() == 2);
2021 CONVERT_CHECKED(JSFunction, fun, args[0]);
2022 CONVERT_CHECKED(Smi, length, args[1]);
2023 MaybeObject* maybe_name =
2024 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2025 String* name;
2026 if (!maybe_name->To(&name)) return maybe_name;
2027 PropertyAttributes attr =
2028 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2029 return fun->AddProperty(name, length, attr, kNonStrictMode);
2030 }
2031
2032
2033 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) { 2006 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
2034 NoHandleAllocation ha; 2007 NoHandleAllocation ha;
2035 ASSERT(args.length() == 2); 2008 ASSERT(args.length() == 2);
2036 2009
2037 CONVERT_CHECKED(JSFunction, fun, args[0]); 2010 CONVERT_CHECKED(JSFunction, fun, args[0]);
2038 ASSERT(fun->should_have_prototype()); 2011 ASSERT(fun->should_have_prototype());
2039 Object* obj; 2012 Object* obj;
2040 { MaybeObject* maybe_obj = 2013 { MaybeObject* maybe_obj =
2041 Accessors::FunctionSetPrototype(fun, args[1], NULL); 2014 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2042 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2015 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
(...skipping 5871 matching lines...) Expand 10 before | Expand all | Expand 10 after
7914 // directly to properties. 7887 // directly to properties.
7915 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED; 7888 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
7916 Handle<JSFunction> result = 7889 Handle<JSFunction> result =
7917 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, 7890 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7918 context, 7891 context,
7919 pretenure_flag); 7892 pretenure_flag);
7920 return *result; 7893 return *result;
7921 } 7894 }
7922 7895
7923 7896
7924 static SmartArrayPointer<Handle<Object> > GetNonBoundArguments( 7897 // Find the arguments of the JavaScript function invocation that called
7925 int bound_argc, 7898 // into C++ code. Collect these in a newly allocated array of handles (possibly
7899 // prefixed by a number of empty handles).
7900 static SmartArrayPointer<Handle<Object> > GetCallerArguments(
7901 int prefix_argc,
7926 int* total_argc) { 7902 int* total_argc) {
7927 // Find frame containing arguments passed to the caller. 7903 // Find frame containing arguments passed to the caller.
7928 JavaScriptFrameIterator it; 7904 JavaScriptFrameIterator it;
7929 JavaScriptFrame* frame = it.frame(); 7905 JavaScriptFrame* frame = it.frame();
7930 List<JSFunction*> functions(2); 7906 List<JSFunction*> functions(2);
7931 frame->GetFunctions(&functions); 7907 frame->GetFunctions(&functions);
7932 if (functions.length() > 1) { 7908 if (functions.length() > 1) {
7933 int inlined_frame_index = functions.length() - 1; 7909 int inlined_frame_index = functions.length() - 1;
7934 JSFunction* inlined_function = functions[inlined_frame_index]; 7910 JSFunction* inlined_function = functions[inlined_frame_index];
7935 int args_count = inlined_function->shared()->formal_parameter_count(); 7911 int args_count = inlined_function->shared()->formal_parameter_count();
7936 ScopedVector<SlotRef> args_slots(args_count); 7912 ScopedVector<SlotRef> args_slots(args_count);
7937 SlotRef::ComputeSlotMappingForArguments(frame, 7913 SlotRef::ComputeSlotMappingForArguments(frame,
7938 inlined_frame_index, 7914 inlined_frame_index,
7939 &args_slots); 7915 &args_slots);
7940 7916
7941 *total_argc = bound_argc + args_count; 7917 *total_argc = prefix_argc + args_count;
7942 SmartArrayPointer<Handle<Object> > param_data( 7918 SmartArrayPointer<Handle<Object> > param_data(
7943 NewArray<Handle<Object> >(*total_argc)); 7919 NewArray<Handle<Object> >(*total_argc));
7944 for (int i = 0; i < args_count; i++) { 7920 for (int i = 0; i < args_count; i++) {
7945 Handle<Object> val = args_slots[i].GetValue(); 7921 Handle<Object> val = args_slots[i].GetValue();
7946 param_data[bound_argc + i] = val; 7922 param_data[prefix_argc + i] = val;
7947 } 7923 }
7948 return param_data; 7924 return param_data;
7949 } else { 7925 } else {
7950 it.AdvanceToArgumentsFrame(); 7926 it.AdvanceToArgumentsFrame();
7951 frame = it.frame(); 7927 frame = it.frame();
7952 int args_count = frame->ComputeParametersCount(); 7928 int args_count = frame->ComputeParametersCount();
7953 7929
7954 *total_argc = bound_argc + args_count; 7930 *total_argc = prefix_argc + args_count;
7955 SmartArrayPointer<Handle<Object> > param_data( 7931 SmartArrayPointer<Handle<Object> > param_data(
7956 NewArray<Handle<Object> >(*total_argc)); 7932 NewArray<Handle<Object> >(*total_argc));
7957 for (int i = 0; i < args_count; i++) { 7933 for (int i = 0; i < args_count; i++) {
7958 Handle<Object> val = Handle<Object>(frame->GetParameter(i)); 7934 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7959 param_data[bound_argc + i] = val; 7935 param_data[prefix_argc + i] = val;
7960 } 7936 }
7961 return param_data; 7937 return param_data;
7962 } 7938 }
7963 } 7939 }
7964 7940
7965 7941
7942 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7943 HandleScope scope(isolate);
7944 ASSERT(args.length() == 3);
7945 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
7946 Handle<Object> bindee = args.at<Object>(1);
7947
7948 // TODO(lrn): Create bound function in C++ code from premade shared info.
7949 bound_function->shared()->set_bound(true);
7950 // Get all arguments of calling function (Function.prototype.bind).
7951 int argc = 0;
7952 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
7953 // Don't count the this-arg.
7954 if (argc > 0) {
7955 ASSERT(*arguments[0] == args[2]);
7956 argc--;
7957 } else {
7958 ASSERT(args[2]->IsUndefined());
7959 }
7960 // Initialize array of bindings (function, this, and any existing arguments
7961 // if the function was already bound).
7962 int total_argc;
7963 Handle<FixedArray> new_bindings;
7964 int i;
7965 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7966 Handle<FixedArray> old_bindings(
7967 JSFunction::cast(*bindee)->function_bindings());
7968 new_bindings =
7969 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
7970 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
7971 i = 0;
7972 for (int n = old_bindings->length(); i < n; i++) {
7973 new_bindings->set(i, old_bindings->get(i));
7974 }
7975 total_argc = argc +
7976 old_bindings->length() - JSFunction::kBoundArgumentsStartIndex;
7977 } else {
7978 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7979 new_bindings = isolate->factory()->NewFixedArray(array_size);
7980 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7981 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7982 i = 2;
7983 total_argc = argc;
7984 }
7985 // Copy arguments, skipping the first which is "this_arg".
7986 for (int j = 0; j < argc; j++, i++) {
7987 new_bindings->set(i, *arguments[j + 1]);
7988 }
7989 new_bindings->set_map(isolate->heap()->fixed_cow_array_map());
7990 bound_function->set_function_bindings(*new_bindings);
7991 // Update length.
7992 if (!bindee->IsJSFunction()) {
7993 bindee = Execution::GetFunctionDelegate(bindee);
rossberg 2011/10/13 14:25:01 Unfortunately, that is not quite right for proxies
Lasse Reichstein 2011/10/14 11:19:37 I think it's an easy fix, if we just read the leng
rossberg 2011/10/17 11:49:08 Yes, that's one of the spec issues I raised. The c
7994 }
7995 int length = JSFunction::cast(*bindee)->shared()->length();
7996 int new_length = length - total_argc;
7997 if (new_length < 0) new_length = 0;
7998 Handle<String> length_symbol = isolate->factory()->length_symbol();
7999 PropertyAttributes attr =
8000 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8001 ForceSetProperty(bound_function, length_symbol,
8002 Handle<Smi>(Smi::FromInt(new_length)), attr);
8003 return *bound_function;
8004 }
8005
8006
8007 RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8008 HandleScope handles(isolate);
8009 ASSERT(args.length() == 1);
8010 CONVERT_ARG_CHECKED(JSObject, callable, 0);
8011 if (callable->IsJSFunction()) {
8012 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8013 if (function->shared()->bound()) {
8014 Handle<FixedArray> bindings(function->function_bindings());
8015 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8016 return *isolate->factory()->NewJSArrayWithElements(bindings);
8017 }
8018 }
8019 return isolate->heap()->undefined_value();
8020 }
8021
8022
7966 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) { 8023 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
7967 HandleScope scope(isolate); 8024 HandleScope scope(isolate);
7968 ASSERT(args.length() == 2); 8025 ASSERT(args.length() == 1);
7969 // First argument is a function to use as a constructor. 8026 // First argument is a function to use as a constructor.
7970 CONVERT_ARG_CHECKED(JSFunction, function, 0); 8027 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8028 RUNTIME_ASSERT(function->shared()->bound());
7971 8029
7972 // Second argument is either null or an array of bound arguments. 8030 // The argument is a bound function. Extract its bound arguments
7973 Handle<FixedArray> bound_args; 8031 // and callable.
7974 int bound_argc = 0; 8032 Handle<FixedArray> bound_args =
7975 if (!args[1]->IsNull()) { 8033 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7976 CONVERT_ARG_CHECKED(JSArray, params, 1); 8034 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7977 RUNTIME_ASSERT(params->HasFastTypeElements()); 8035 Handle<Object> bound_function(
7978 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements())); 8036 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
7979 bound_argc = Smi::cast(params->length())->value(); 8037 ASSERT(!bound_function->IsJSFunction() ||
7980 } 8038 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
7981 8039
7982 int total_argc = 0; 8040 int total_argc = 0;
7983 SmartArrayPointer<Handle<Object> > param_data = 8041 SmartArrayPointer<Handle<Object> > param_data =
7984 GetNonBoundArguments(bound_argc, &total_argc); 8042 GetCallerArguments(bound_argc, &total_argc);
7985 for (int i = 0; i < bound_argc; i++) { 8043 for (int i = 0; i < bound_argc; i++) {
7986 Handle<Object> val = Handle<Object>(bound_args->get(i)); 8044 param_data[i] = Handle<Object>(bound_args->get(
7987 param_data[i] = val; 8045 JSFunction::kBoundArgumentsStartIndex + i));
7988 } 8046 }
7989 8047
8048 if (!bound_function->IsJSFunction()) {
8049 bool exception_thrown;
8050 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8051 &exception_thrown);
8052 if (exception_thrown) return Failure::Exception();
8053 }
8054 ASSERT(bound_function->IsJSFunction());
8055
7990 bool exception = false; 8056 bool exception = false;
7991 Handle<Object> result = 8057 Handle<Object> result =
7992 Execution::New(function, total_argc, *param_data, &exception); 8058 Execution::New(Handle<JSFunction>::cast(bound_function),
8059 total_argc, *param_data, &exception);
7993 if (exception) { 8060 if (exception) {
7994 return Failure::Exception(); 8061 return Failure::Exception();
7995 } 8062 }
7996
7997 ASSERT(!result.is_null()); 8063 ASSERT(!result.is_null());
7998 return *result; 8064 return *result;
7999 } 8065 }
8000 8066
8001 8067
8002 static void TrySettingInlineConstructStub(Isolate* isolate, 8068 static void TrySettingInlineConstructStub(Isolate* isolate,
8003 Handle<JSFunction> function) { 8069 Handle<JSFunction> function) {
8004 Handle<Object> prototype = isolate->factory()->null_value(); 8070 Handle<Object> prototype = isolate->factory()->null_value();
8005 if (function->has_instance_prototype()) { 8071 if (function->has_instance_prototype()) {
8006 prototype = Handle<Object>(function->instance_prototype(), isolate); 8072 prototype = Handle<Object>(function->instance_prototype(), isolate);
(...skipping 5236 matching lines...) Expand 10 before | Expand all | Expand 10 after
13243 } else { 13309 } else {
13244 // Handle last resort GC and make sure to allow future allocations 13310 // Handle last resort GC and make sure to allow future allocations
13245 // to grow the heap without causing GCs (if possible). 13311 // to grow the heap without causing GCs (if possible).
13246 isolate->counters()->gc_last_resort_from_js()->Increment(); 13312 isolate->counters()->gc_last_resort_from_js()->Increment();
13247 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags); 13313 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
13248 } 13314 }
13249 } 13315 }
13250 13316
13251 13317
13252 } } // namespace v8::internal 13318 } } // namespace v8::internal
OLDNEW
« src/objects.h ('K') | « src/runtime.h ('k') | src/runtime.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698