Commit 64923a6a authored by kasperl@chromium.org's avatar kasperl@chromium.org

Generalize the Function.prototype.call hooks in the

arguments adaptor code to allow builtins to work without
argument adaptor frames. Get rid of unused JavaScript
implementation of call and apply and the associated
code generation hooks.
Review URL: http://codereview.chromium.org/2850

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@311 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent cf1a6a0b
......@@ -956,33 +956,37 @@ bool Genesis::InstallNatives() {
InstallNativeFunctions();
// TODO(1240778): Get rid of the JS implementation of
// Function.prototype.call and simply create a function with the
// faked formal parameter count (-1) and use the illegal builtin as
// the code for it.
// Find Function.prototype.call and set it's number of formal
// parameters to -1 to let the arguments adaptor handle it
// specially.
{ Handle<JSFunction> function =
Handle<JSFunction>::cast(GetProperty(Top::global(),
Factory::function_class_symbol()));
// Install Function.prototype.call and apply.
{ Handle<String> key = Factory::function_class_symbol();
Handle<JSFunction> function =
Handle<JSFunction>::cast(GetProperty(Top::global(), key));
Handle<JSObject> proto =
Handle<JSObject>(JSObject::cast(function->instance_prototype()));
// Install the call and the apply functions.
Handle<JSFunction> call =
Handle<JSFunction>::cast(GetProperty(proto, Factory::call_symbol()));
call->shared()->set_formal_parameter_count(-1);
InstallFunction(proto, "call", JS_OBJECT_TYPE, JSObject::kHeaderSize,
Factory::NewJSObject(Top::object_function(), TENURED),
Builtins::FunctionCall,
false);
Handle<JSFunction> apply =
InstallFunction(proto, "apply", JS_OBJECT_TYPE, JSObject::kHeaderSize,
Factory::NewJSObject(Top::object_function(), TENURED),
Builtins::FunctionApply,
false);
// Make sure that Function.prototype.call appears to be compiled.
// The code will never be called, but inline caching for call will
// only work if it appears to be compiled.
call->shared()->set_code(Builtins::builtin(Builtins::Illegal));
call->shared()->DontAdaptArguments();
ASSERT(call->is_compiled());
// Use the specialized builtin for Function.prototype.apply.
Handle<JSFunction> apply =
Handle<JSFunction>::cast(GetProperty(proto, Factory::apply_symbol()));
apply->shared()->set_code(Builtins::builtin(Builtins::FunctionApply));
// Set the expected paramters for apply to 2; required by builtin.
apply->shared()->set_formal_parameter_count(2);
// Set the lengths for the functions to satisfy ECMA-262.
call->shared()->set_length(1);
apply->shared()->set_length(2);
}
// Make sure that the builtins object has fast properties.
......
This diff is collapsed.
......@@ -379,6 +379,135 @@ void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
}
void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
// 1. Make sure we have at least one argument.
{ Label done;
__ test(eax, Operand(eax));
__ j(not_zero, &done, taken);
__ pop(ebx);
__ push(Immediate(Factory::undefined_value()));
__ push(ebx);
__ inc(eax);
__ bind(&done);
}
// 2. Get the function to call from the stack.
{ Label done, non_function, function;
// +1 ~ return address.
__ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize));
__ test(edi, Immediate(kSmiTagMask));
__ j(zero, &non_function, not_taken);
__ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); // get the map
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ cmp(ecx, JS_FUNCTION_TYPE);
__ j(equal, &function, taken);
// Non-function called: Clear the function to force exception.
__ bind(&non_function);
__ xor_(edi, Operand(edi));
__ jmp(&done);
// Function called: Change context eagerly to get the right global object.
__ bind(&function);
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
__ bind(&done);
}
// 3. Make sure first argument is an object; convert if necessary.
{ Label call_to_object, use_global_receiver, patch_receiver, done;
__ mov(ebx, Operand(esp, eax, times_4, 0));
__ test(ebx, Immediate(kSmiTagMask));
__ j(zero, &call_to_object);
__ cmp(ebx, Factory::null_value());
__ j(equal, &use_global_receiver);
__ cmp(ebx, Factory::undefined_value());
__ j(equal, &use_global_receiver);
__ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
__ j(less, &call_to_object);
__ cmp(ecx, LAST_JS_OBJECT_TYPE);
__ j(less_equal, &done);
__ bind(&call_to_object);
__ EnterInternalFrame(); // preserves eax, ebx, edi
// Store the arguments count on the stack (smi tagged).
ASSERT(kSmiTag == 0);
__ shl(eax, kSmiTagSize);
__ push(eax);
__ push(edi); // save edi across the call
__ push(ebx);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
__ mov(Operand(ebx), eax);
__ pop(edi); // restore edi after the call
// Get the arguments count and untag it.
__ pop(eax);
__ shr(eax, kSmiTagSize);
__ ExitInternalFrame();
__ jmp(&patch_receiver);
// Use the global object from the called function as the receiver.
__ bind(&use_global_receiver);
const int kGlobalIndex =
Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
__ mov(ebx, FieldOperand(esi, kGlobalIndex));
__ bind(&patch_receiver);
__ mov(Operand(esp, eax, times_4, 0), ebx);
__ bind(&done);
}
// 4. Shift stuff one slot down the stack.
{ Label loop;
__ lea(ecx, Operand(eax, +1)); // +1 ~ copy receiver too
__ bind(&loop);
__ mov(ebx, Operand(esp, ecx, times_4, 0));
__ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
__ dec(ecx);
__ j(not_zero, &loop);
}
// 5. Remove TOS (copy of last arguments), but keep return address.
__ pop(ebx);
__ pop(ecx);
__ push(ebx);
__ dec(eax);
// 6. Check that function really was a function and get the code to
// call from the function and check that the number of expected
// arguments matches what we're providing.
{ Label invoke;
__ test(edi, Operand(edi));
__ j(not_zero, &invoke, taken);
__ xor_(ebx, Operand(ebx));
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
__ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), code_target);
__ bind(&invoke);
__ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ mov(ebx,
FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
__ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
__ lea(edx, FieldOperand(edx, Code::kHeaderSize));
__ cmp(eax, Operand(ebx));
__ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline)));
}
// 7. Jump (tail-call) to the code in register edx without checking arguments.
ParameterCount expected(0);
__ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION);
}
void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ EnterInternalFrame();
......@@ -530,15 +659,14 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// -- edx : code entry to call
// -----------------------------------
Label entry, invoke, function_prototype_call;
__ bind(&entry);
Label invoke, dont_adapt_arguments;
__ IncrementCounter(&Counters::arguments_adaptors, 1);
Label enough, too_few;
__ cmp(eax, Operand(ebx));
__ j(less, &too_few);
__ cmp(ebx, -1);
__ j(equal, &function_prototype_call);
__ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
__ j(equal, &dont_adapt_arguments);
{ // Enough parameters: Actual >= expected.
__ bind(&enough);
......@@ -604,135 +732,10 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// -------------------------------------------
// Function.prototype.call implementation.
// Dont adapt arguments.
// -------------------------------------------
__ bind(&function_prototype_call);
// 1. Make sure we have at least one argument.
{ Label done;
__ test(eax, Operand(eax));
__ j(not_zero, &done, taken);
__ pop(ebx);
__ push(Immediate(Factory::undefined_value()));
__ push(ebx);
__ inc(eax);
__ bind(&done);
}
// 2. Get the function to call from the stack.
{ Label done, non_function, function;
// +1 ~ return address.
__ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize));
__ test(edi, Immediate(kSmiTagMask));
__ j(zero, &non_function, not_taken);
__ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); // get the map
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ cmp(ecx, JS_FUNCTION_TYPE);
__ j(equal, &function, taken);
// Non-function called: Clear the function to force exception.
__ bind(&non_function);
__ xor_(edi, Operand(edi));
__ jmp(&done);
// Function called: Change context eagerly to get the right global object.
__ bind(&function);
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
__ bind(&done);
}
// 3. Make sure first argument is an object; convert if necessary.
{ Label call_to_object, use_global_receiver, patch_receiver, done;
__ mov(ebx, Operand(esp, eax, times_4, 0));
__ test(ebx, Immediate(kSmiTagMask));
__ j(zero, &call_to_object);
__ cmp(ebx, Factory::null_value());
__ j(equal, &use_global_receiver);
__ cmp(ebx, Factory::undefined_value());
__ j(equal, &use_global_receiver);
__ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
__ j(less, &call_to_object);
__ cmp(ecx, LAST_JS_OBJECT_TYPE);
__ j(less_equal, &done);
__ bind(&call_to_object);
__ EnterInternalFrame(); // preserves eax, ebx, edi
// Store the arguments count on the stack (smi tagged).
ASSERT(kSmiTag == 0);
__ shl(eax, kSmiTagSize);
__ push(eax);
__ push(edi); // save edi across the call
__ push(ebx);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
__ mov(Operand(ebx), eax);
__ pop(edi); // restore edi after the call
// Get the arguments count and untag it.
__ pop(eax);
__ shr(eax, kSmiTagSize);
__ ExitInternalFrame();
__ jmp(&patch_receiver);
// Use the global object from the called function as the receiver.
__ bind(&use_global_receiver);
const int kGlobalIndex =
Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
__ mov(ebx, FieldOperand(esi, kGlobalIndex));
__ bind(&patch_receiver);
__ mov(Operand(esp, eax, times_4, 0), ebx);
__ bind(&done);
}
// 4. Shift stuff one slot down the stack.
{ Label loop;
__ lea(ecx, Operand(eax, +1)); // +1 ~ copy receiver too
__ bind(&loop);
__ mov(ebx, Operand(esp, ecx, times_4, 0));
__ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
__ dec(ecx);
__ j(not_zero, &loop);
}
// 5. Remove TOS (copy of last arguments), but keep return address.
__ pop(ebx);
__ pop(ecx);
__ push(ebx);
__ dec(eax);
// 6. Check that function really was a function and get the code to
// call from the function and check that the number of expected
// arguments matches what we're providing.
{ Label invoke;
__ test(edi, Operand(edi));
__ j(not_zero, &invoke, taken);
__ xor_(ebx, Operand(ebx));
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
__ jmp(&enough);
__ bind(&invoke);
__ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ mov(ebx,
FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
__ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
__ lea(edx, FieldOperand(edx, Code::kHeaderSize));
__ cmp(eax, Operand(ebx));
__ j(not_equal, &entry);
}
// 7. Jump (tail-call) to the code in register edx without checking arguments.
ParameterCount expected(0);
__ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION);
__ bind(&dont_adapt_arguments);
__ jmp(Operand(edx));
}
......
......@@ -28,11 +28,8 @@
#ifndef V8_BUILTINS_H_
#define V8_BUILTINS_H_
namespace v8 { namespace internal {
// Define list of builtins implemented in C.
#define BUILTIN_LIST_C(V) \
V(Illegal, 0) \
......@@ -90,6 +87,7 @@ namespace v8 { namespace internal {
V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK) \
\
/* Uses KeyedLoadIC_Initialize; must be after in list. */ \
V(FunctionCall, BUILTIN, UNINITIALIZED) \
V(FunctionApply, BUILTIN, UNINITIALIZED)
......@@ -219,6 +217,8 @@ class Builtins : public AllStatic {
static void Generate_JSEntryTrampoline(MacroAssembler* masm);
static void Generate_JSConstructEntryTrampoline(MacroAssembler* masm);
static void Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm);
static void Generate_FunctionCall(MacroAssembler* masm);
static void Generate_FunctionApply(MacroAssembler* masm);
static void Generate_LoadIC_DebugBreak(MacroAssembler* masm);
......@@ -231,7 +231,6 @@ class Builtins : public AllStatic {
static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm);
};
} } // namespace v8::internal
#endif // V8_BUILTINS_H_
......@@ -305,16 +305,6 @@ class ArmCodeGenerator: public CodeGenerator {
void EnterJSFrame();
void ExitJSFrame();
virtual void GenerateShiftDownAndTailCall(ZoneList<Expression*>* args);
virtual void GenerateSetThisFunction(ZoneList<Expression*>* args);
virtual void GenerateGetThisFunction(ZoneList<Expression*>* args);
virtual void GenerateSetThis(ZoneList<Expression*>* args);
virtual void GenerateGetArgumentsLength(ZoneList<Expression*>* args);
virtual void GenerateSetArgumentsLength(ZoneList<Expression*>* args);
virtual void GenerateTailCallWithArguments(ZoneList<Expression*>* args);
virtual void GenerateSetArgument(ZoneList<Expression*>* args);
virtual void GenerateSquashFrame(ZoneList<Expression*>* args);
virtual void GenerateExpandFrame(ZoneList<Expression*>* args);
virtual void GenerateIsSmi(ZoneList<Expression*>* args);
virtual void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
virtual void GenerateIsArray(ZoneList<Expression*>* args);
......@@ -3834,31 +3824,6 @@ void ArmCodeGenerator::VisitCallNew(CallNew* node) {
}
void ArmCodeGenerator::GenerateSetThisFunction(ZoneList<Expression*>* args) {
__ stop("ArmCodeGenerator::GenerateSetThisFunction - unreachable");
}
void ArmCodeGenerator::GenerateGetThisFunction(ZoneList<Expression*>* args) {
__ stop("ArmCodeGenerator::GenerateGetThisFunction - unreachable");
}
void ArmCodeGenerator::GenerateSetThis(ZoneList<Expression*>* args) {
__ stop("ArmCodeGenerator::GenerateSetThis - unreachable");
}
void ArmCodeGenerator::GenerateSetArgumentsLength(ZoneList<Expression*>* args) {
__ stop("ArmCodeGenerator::GenerateSetArgumentsLength - unreachable");
}
void ArmCodeGenerator::GenerateGetArgumentsLength(ZoneList<Expression*>* args) {
__ stop("ArmCodeGenerator::GenerateGetArgumentsLength - unreachable");
}
void ArmCodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Label leave;
......@@ -3907,27 +3872,6 @@ void ArmCodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
}
void ArmCodeGenerator::GenerateTailCallWithArguments(
ZoneList<Expression*>* args) {
__ stop("ArmCodeGenerator::GenerateTailCallWithArguments - unreachable");
}
void ArmCodeGenerator::GenerateSetArgument(ZoneList<Expression*>* args) {
__ stop("ArmCodeGenerator::GenerateSetArgument - unreachable");
}
void ArmCodeGenerator::GenerateSquashFrame(ZoneList<Expression*>* args) {
__ stop("ArmCodeGenerator::GenerateSquashFrame - unreachable");
}
void ArmCodeGenerator::GenerateExpandFrame(ZoneList<Expression*>* args) {
__ stop("ArmCodeGenerator::GenerateExpandFrame - unreachable");
}
void ArmCodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
......@@ -4020,12 +3964,6 @@ void ArmCodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
}
void ArmCodeGenerator::GenerateShiftDownAndTailCall(
ZoneList<Expression*>* args) {
__ stop("ArmCodeGenerator::GenerateShiftDownAndTailCall - unreachable");
}
void ArmCodeGenerator::VisitCallRuntime(CallRuntime* node) {
if (CheckForInlineRuntimeCall(node)) return;
......
......@@ -320,16 +320,6 @@ class Ia32CodeGenerator: public CodeGenerator {
void EnterJSFrame();
void ExitJSFrame();
virtual void GenerateShiftDownAndTailCall(ZoneList<Expression*>* args);
virtual void GenerateSetThisFunction(ZoneList<Expression*>* args);
virtual void GenerateGetThisFunction(ZoneList<Expression*>* args);
virtual void GenerateSetThis(ZoneList<Expression*>* args);
virtual void GenerateGetArgumentsLength(ZoneList<Expression*>* args);
virtual void GenerateSetArgumentsLength(ZoneList<Expression*>* args);
virtual void GenerateTailCallWithArguments(ZoneList<Expression*>* args);
virtual void GenerateSetArgument(ZoneList<Expression*>* args);
virtual void GenerateSquashFrame(ZoneList<Expression*>* args);
virtual void GenerateExpandFrame(ZoneList<Expression*>* args);
virtual void GenerateIsSmi(ZoneList<Expression*>* args);
virtual void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
virtual void GenerateIsArray(ZoneList<Expression*>* args);
......@@ -4035,70 +4025,6 @@ void Ia32CodeGenerator::VisitCallNew(CallNew* node) {
}
void Ia32CodeGenerator::GenerateSetThisFunction(ZoneList<Expression*>* args) {
// Not used on IA-32 anymore. Should go away soon.
__ int3();
}
void Ia32CodeGenerator::GenerateGetThisFunction(ZoneList<Expression*>* args) {
// Not used on IA-32 anymore. Should go away soon.
__ int3();
}
void Ia32CodeGenerator::GenerateSetThis(ZoneList<Expression*>* args) {
// Not used on IA-32 anymore. Should go away soon.
__ int3();
}
void Ia32CodeGenerator::GenerateSetArgumentsLength(
ZoneList<Expression*>* args) {
// Not used on IA-32 anymore. Should go away soon.
__ int3();
}
void Ia32CodeGenerator::GenerateGetArgumentsLength(
ZoneList<Expression*>* args) {
// Not used on IA-32 anymore. Should go away soon.
__ int3();
}
void Ia32CodeGenerator::GenerateTailCallWithArguments(
ZoneList<Expression*>* args) {
// Not used on IA-32 anymore. Should go away soon.
__ int3();
}
void Ia32CodeGenerator::GenerateSetArgument(ZoneList<Expression*>* args) {
// Not used on IA-32 anymore. Should go away soon.
__ int3();
}
void Ia32CodeGenerator::GenerateSquashFrame(ZoneList<Expression*>* args) {
// Not used on IA-32 anymore. Should go away soon.
__ int3();
}
void Ia32CodeGenerator::GenerateExpandFrame(ZoneList<Expression*>* args) {
// Not used on IA-32 anymore. Should go away soon.
__ int3();
}
void Ia32CodeGenerator::GenerateShiftDownAndTailCall(
ZoneList<Expression*>* args) {
// Not used on IA-32 anymore. Should go away soon.
__ int3();
}
void Ia32CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
......
......@@ -216,26 +216,6 @@ bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
// for implementing Function.prototype.call() and
// Function.prototype.apply().
static const InlineRuntimeLUT kInlineRuntimeLUT[] = {
{&v8::internal::CodeGenerator::GenerateShiftDownAndTailCall,
"_ShiftDownAndTailCall"},
{&v8::internal::CodeGenerator::GenerateSetThisFunction,
"_SetThisFunction"},
{&v8::internal::CodeGenerator::GenerateGetThisFunction,
"_GetThisFunction"},
{&v8::internal::CodeGenerator::GenerateSetThis,
"_SetThis"},
{&v8::internal::CodeGenerator::GenerateGetArgumentsLength,
"_GetArgumentsLength"},
{&v8::internal::CodeGenerator::GenerateSetArgumentsLength,
"_SetArgumentsLength"},
{&v8::internal::CodeGenerator::GenerateTailCallWithArguments,
"_TailCallWithArguments"},
{&v8::internal::CodeGenerator::GenerateSetArgument,
"_SetArgument"},
{&v8::internal::CodeGenerator::GenerateSquashFrame,
"_SquashFrame"},
{&v8::internal::CodeGenerator::GenerateExpandFrame,
"_ExpandFrame"},
{&v8::internal::CodeGenerator::GenerateIsSmi,
"_IsSmi"},
{&v8::internal::CodeGenerator::GenerateIsNonNegativeSmi,
......
......@@ -147,16 +147,7 @@ class CodeGenerator: public Visitor {
// name/value pairs.
virtual void DeclareGlobals(Handle<FixedArray> pairs) = 0;
virtual void GenerateShiftDownAndTailCall(ZoneList<Expression*>* args) = 0;
virtual void GenerateSetThisFunction(ZoneList<Expression*>* args) = 0;
virtual void GenerateGetThisFunction(ZoneList<Expression*>* args) = 0;
virtual void GenerateSetThis(ZoneList<Expression*>* args) = 0;
virtual void GenerateGetArgumentsLength(ZoneList<Expression*>* args) = 0;
virtual void GenerateSetArgumentsLength(ZoneList<Expression*>* args) = 0;
virtual void GenerateTailCallWithArguments(ZoneList<Expression*>* args) = 0;
virtual void GenerateSetArgument(ZoneList<Expression*>* args) = 0;
virtual void GenerateSquashFrame(ZoneList<Expression*>* args) = 0;
virtual void GenerateExpandFrame(ZoneList<Expression*>* args) = 0;
// Support for type checks.
virtual void GenerateIsSmi(ZoneList<Expression*>* args) = 0;
virtual void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) = 0;
virtual void GenerateIsArray(ZoneList<Expression*>* args) = 0;
......
......@@ -1782,6 +1782,11 @@ INT_ACCESSORS(SharedFunctionInfo, function_token_position,
kFunctionTokenPositionOffset)
void SharedFunctionInfo::DontAdaptArguments() {
set_formal_parameter_count(kDontAdaptArgumentsSentinel);
}
int SharedFunctionInfo::start_position() {
return start_position_and_type() >> kStartPositionShift;
}
......
......@@ -2464,6 +2464,10 @@ class SharedFunctionInfo: public HeapObject {
inline int formal_parameter_count();
inline void set_formal_parameter_count(int value);
// Set the formal parameter count so the function code will be
// called without using argument adaptor frames.
inline void DontAdaptArguments();
// [expected_nof_properties]: Expected number of properties for the function.
inline int expected_nof_properties();
inline void set_expected_nof_properties(int value);
......@@ -2533,6 +2537,9 @@ class SharedFunctionInfo: public HeapObject {
// Casting.
static inline SharedFunctionInfo* cast(Object* obj);
// Constants.
static const int kDontAdaptArgumentsSentinel = -1;
// Layout description.
static const int kNameOffset = HeapObject::kSize;
static const int kCodeOffset = kNameOffset + kPointerSize;
......
......@@ -414,107 +414,3 @@ function NewFunction(arg1) { // length == 1
};
%SetCode($Function, NewFunction);
// NOTE: The following functions (call and apply) are only used in this
// form on the ARM platform. On IA-32 they are handled through specialized
// builtins; see builtins-ia32.cc.
%AddProperty($Function.prototype, "call", function(receiver) {
// Make sure the receiver of this call is a function. If it isn't
// we "fake" a call of it (without the right arguments) to force
// an exception to be thrown.
if (!IS_FUNCTION(this)) this();
// If receiver is null or undefined set the receiver to the global
// object. If the receiver isn't an object, we convert the
// receiver to an object.
if (receiver == null) receiver = global;
else if (!IS_OBJECT(receiver)) receiver = ToObject(receiver);
%_SetThisFunction(this);
%_SetThis(receiver);
var len = %_GetArgumentsLength(1);
return %_ShiftDownAndTailCall(len ? len - 1 : 0);
}, DONT_ENUM);
// This implementation of Function.prototype.apply replaces the stack frame
// of the apply call with the new stack frame containing the arguments from
// the args array.
%AddProperty($Function.prototype, "apply", function(receiver, args) {
var length = (args == null) ? 0 : ToUint32(args.length);
// We can handle any number of apply arguments if the stack is
// big enough, but sanity check the value to avoid overflow when
// multiplying with pointer size.
if (length > 0x800000) {
throw new $RangeError(
"Function.prototype.apply cannot support " + length + " arguments.");
}
if (!IS_FUNCTION(this)) {
throw new $TypeError('Function.prototype.apply was called on ' + this.toString() + ', which is a ' + (typeof this) + ' and not a function');
}
// Make sure args has the right type.
if (args != null && %ClassOf(args) !== 'Array' && %ClassOf(args) !== 'Arguments') {
throw new $TypeError('Function.prototype.apply: args has wrong type');
}
// If receiver is null or undefined set the receiver to the global
// object. If the receiver isn't an object, we convert the
// receiver to an object.
if (receiver == null) receiver = global;
else if (!IS_OBJECT(receiver)) receiver = ToObject(receiver);
%_SetThisFunction(this);
%_SetThis(receiver);
var arguments_length = %_GetArgumentsLength(2);
// This method has 2 formal arguments so if less are passed, then space has
// been made.
if (arguments_length < 2)
arguments_length = 2;
// Move some stuff to locals so they don't get overwritten when we start
// expanding the args array.
var saved_args = args;
if (arguments_length > length) {
// We have too many arguments - we need to squash the frame.
%_SquashFrame(arguments_length, length);
} else if (arguments_length != length) {
// We have too few spaces for arguments - we need to expand the frame.
if (!%_ExpandFrame(arguments_length, length)) {
throw new $RangeError(
"Function.prototype.apply cannot find stack space for " + length + " arguments.");
}
// GC doesn't like junk in the arguments!
for (var i = 0; i < length; i++) {
%_SetArgument(i, 0, length);
}
}
// Update-number-of-arguments field to keep things looking consistent for
// stack traces, and uses of arguments or arguments.length.
%_SetArgumentsLength(length);
// NOTE: For the fast case this should be implemented in assembler,
// which would allow us to omit bounds and class checks galore. The
// assembler version could fall back to this implementation if
// tricky stuff is found, like arrays implemented as dictionaries or
// holes in arrays.
for (var i = 0; i < length; i++) {
%_SetArgument(i, saved_args[i], length);
}
// Replaces the current frame with the new call. This has the added effect
// of removing apply from the stack trace entirely, which matches the
// behaviour of Firefox.
return %_TailCallWithArguments(length);
}, DONT_ENUM);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment