void CallFunctionStub::Generate(MacroAssembler* masm) {
+ // r1 : the function to call
Label slow, non_function;
// The receiver might implicitly be the global object. This is
__ CompareRoot(r4, Heap::kTheHoleValueRootIndex);
__ b(ne, &call);
// Patch the receiver on the stack with the global receiver object.
- __ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
- __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
- __ str(r1, MemOperand(sp, argc_ * kPointerSize));
+ __ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
+ __ str(r2, MemOperand(sp, argc_ * kPointerSize));
__ bind(&call);
}
- // Get the function to call from the stack.
- // function, receiver [, arguments]
- __ ldr(r1, MemOperand(sp, (argc_ + 1) * kPointerSize));
-
// Check that the function is really a JavaScript function.
// r1: pushed function (to be verified)
__ JumpIfSmi(r1, &non_function);
__ mov(r0, Operand(argc_ + 1, RelocInfo::NONE));
__ mov(r2, Operand(0, RelocInfo::NONE));
__ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY);
- __ SetCallKind(r5, CALL_AS_FUNCTION);
+ __ SetCallKind(r5, CALL_AS_METHOD);
{
Handle<Code> adaptor =
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
}
-void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
+void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // No registers used on entry.
+ // -- r1 : function
// -----------------------------------
- Generate_DebugBreakCallHelper(masm, 0, 0);
+ Generate_DebugBreakCallHelper(masm, r1.bit(), 0);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
CallFunctionStub stub(arg_count, flags);
+ __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
// Record source position for debugger.
SetSourcePosition(expr->position());
CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
+ __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
}
VisitForAccumulatorValue(args->last()); // Function.
+ // Check for proxy.
+ Label proxy, done;
+ __ CompareObjectType(r0, r1, r1, JS_FUNCTION_PROXY_TYPE);
+ __ b(eq, &proxy);
+
// InvokeFunction requires the function in r1. Move it in there.
__ mov(r1, result_register());
ParameterCount count(arg_count);
__ InvokeFunction(r1, count, CALL_FUNCTION,
NullCallWrapper(), CALL_AS_METHOD);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ jmp(&done);
+
+ __ bind(&proxy);
+ __ push(r0);
+ __ CallRuntime(Runtime::kCall, args->length());
+ __ bind(&done);
+
context()->Plug(r0);
}
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
+ LOperand* function = UseFixed(instr->function(), r1);
argument_count_ -= instr->argument_count();
- return MarkAsCall(DefineFixed(new LCallFunction, r0), instr);
+ return MarkAsCall(DefineFixed(new LCallFunction(function), r0), instr);
}
};
-class LCallFunction: public LTemplateInstruction<1, 0, 0> {
+class LCallFunction: public LTemplateInstruction<1, 1, 0> {
public:
+ explicit LCallFunction(LOperand* function) {
+ inputs_[0] = function;
+ }
+
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
DECLARE_HYDROGEN_ACCESSOR(CallFunction)
- int arity() const { return hydrogen()->argument_count() - 2; }
+ LOperand* function() { return inputs_[0]; }
+ int arity() const { return hydrogen()->argument_count() - 1; }
};
void LCodeGen::DoCallFunction(LCallFunction* instr) {
+ ASSERT(ToRegister(instr->function()).is(r1));
ASSERT(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- __ Drop(1);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
}
-static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
- Debug::GenerateStubNoRegistersDebugBreak(masm);
+static void Generate_CallFunctionStub_DebugBreak(MacroAssembler* masm) {
+ Debug::GenerateCallFunctionStubDebugBreak(masm);
}
#ifdef ENABLE_DEBUGGER_SUPPORT
// Define list of builtins used by the debugger implemented in assembly.
-#define BUILTIN_LIST_DEBUG_A(V) \
- V(Return_DebugBreak, BUILTIN, DEBUG_BREAK, \
- Code::kNoExtraICState) \
- V(ConstructCall_DebugBreak, BUILTIN, DEBUG_BREAK, \
- Code::kNoExtraICState) \
- V(StubNoRegisters_DebugBreak, BUILTIN, DEBUG_BREAK, \
- Code::kNoExtraICState) \
- V(LoadIC_DebugBreak, LOAD_IC, DEBUG_BREAK, \
- Code::kNoExtraICState) \
- V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK, \
- Code::kNoExtraICState) \
- V(StoreIC_DebugBreak, STORE_IC, DEBUG_BREAK, \
- Code::kNoExtraICState) \
- V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK, \
- Code::kNoExtraICState) \
- V(Slot_DebugBreak, BUILTIN, DEBUG_BREAK, \
- Code::kNoExtraICState) \
- V(PlainReturn_LiveEdit, BUILTIN, DEBUG_BREAK, \
- Code::kNoExtraICState) \
- V(FrameDropper_LiveEdit, BUILTIN, DEBUG_BREAK, \
- Code::kNoExtraICState)
+#define BUILTIN_LIST_DEBUG_A(V) \
+ V(Return_DebugBreak, BUILTIN, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(ConstructCall_DebugBreak, BUILTIN, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(CallFunctionStub_DebugBreak, BUILTIN, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(LoadIC_DebugBreak, LOAD_IC, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(StoreIC_DebugBreak, STORE_IC, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(Slot_DebugBreak, BUILTIN, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(PlainReturn_LiveEdit, BUILTIN, DEBUG_BREAK, \
+ Code::kNoExtraICState) \
+ V(FrameDropper_LiveEdit, BUILTIN, DEBUG_BREAK, \
+ Code::kNoExtraICState)
#else
#define BUILTIN_LIST_DEBUG_A(V)
#endif
if (code->kind() == Code::STUB) {
ASSERT(code->major_key() == CodeStub::CallFunction);
Handle<Code> result =
- Isolate::Current()->builtins()->StubNoRegisters_DebugBreak();
+ Isolate::Current()->builtins()->CallFunctionStub_DebugBreak();
return result;
}
static void GenerateKeyedStoreICDebugBreak(MacroAssembler* masm);
static void GenerateConstructCallDebugBreak(MacroAssembler* masm);
static void GenerateReturnDebugBreak(MacroAssembler* masm);
- static void GenerateStubNoRegistersDebugBreak(MacroAssembler* masm);
+ static void GenerateCallFunctionStubDebugBreak(MacroAssembler* masm);
static void GenerateSlotDebugBreak(MacroAssembler* masm);
static void GeneratePlainReturnLiveEdit(MacroAssembler* masm);
};
-class HCallFunction: public HUnaryCall {
+class HCallFunction: public HBinaryCall {
public:
- HCallFunction(HValue* context, int argument_count)
- : HUnaryCall(context, argument_count) {
+ HCallFunction(HValue* context, HValue* function, int argument_count)
+ : HBinaryCall(context, function, argument_count) {
}
- HValue* context() { return value(); }
+ HValue* context() { return first(); }
+ HValue* function() { return second(); }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::Tagged();
}
} else {
- CHECK_ALIVE(VisitArgument(expr->expression()));
+ CHECK_ALIVE(VisitForValue(expr->expression()));
+ HValue* function = Top();
HValue* context = environment()->LookupContext();
HGlobalObject* global_object = new(zone()) HGlobalObject(context);
HGlobalReceiver* receiver = new(zone()) HGlobalReceiver(global_object);
PushAndAdd(new(zone()) HPushArgument(receiver));
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
- // The function to call is treated as an argument to the call function
- // stub.
- call = new(zone()) HCallFunction(context, argument_count + 1);
+ call = new(zone()) HCallFunction(context, function, argument_count);
Drop(argument_count + 1);
}
}
CHECK_ALIVE(VisitArgument(call->arguments()->at(i)));
}
CHECK_ALIVE(VisitForValue(call->arguments()->last()));
+
HValue* function = Pop();
HValue* context = environment()->LookupContext();
- HInvokeFunction* result =
- new(zone()) HInvokeFunction(context, function, arg_count);
+
+ // Branch for function proxies, or other non-functions.
+ HHasInstanceTypeAndBranch* typecheck =
+ new(zone()) HHasInstanceTypeAndBranch(function, JS_FUNCTION_TYPE);
+ HBasicBlock* if_jsfunction = graph()->CreateBasicBlock();
+ HBasicBlock* if_nonfunction = graph()->CreateBasicBlock();
+ HBasicBlock* join = graph()->CreateBasicBlock();
+ typecheck->SetSuccessorAt(0, if_jsfunction);
+ typecheck->SetSuccessorAt(1, if_nonfunction);
+ current_block()->Finish(typecheck);
+
+ set_current_block(if_jsfunction);
+ HInstruction* invoke_result = AddInstruction(
+ new(zone()) HInvokeFunction(context, function, arg_count));
Drop(arg_count);
- return ast_context()->ReturnInstruction(result, call->id());
+ Push(invoke_result);
+ if_jsfunction->Goto(join);
+
+ set_current_block(if_nonfunction);
+ HInstruction* call_result = AddInstruction(
+ new(zone()) HCallFunction(context, function, arg_count));
+ Drop(arg_count);
+ Push(call_result);
+ if_nonfunction->Goto(join);
+
+ set_current_block(join);
+ join->SetJoinId(call->id());
+ return ast_context()->ReturnValue(Pop());
}
__ test(edx, edx);
__ j(zero, &function);
__ Set(ebx, Immediate(0));
- __ SetCallKind(ecx, CALL_AS_METHOD);
__ cmp(edx, Immediate(1));
__ j(not_equal, &non_proxy);
__ push(edi); // re-add proxy object as additional argument
__ push(edx);
__ inc(eax);
+ __ SetCallKind(ecx, CALL_AS_FUNCTION);
__ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
__ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
__ bind(&non_proxy);
+ __ SetCallKind(ecx, CALL_AS_METHOD);
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
__ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
void CallFunctionStub::Generate(MacroAssembler* masm) {
+ // edi : the function to call
Isolate* isolate = masm->isolate();
Label slow, non_function;
__ bind(&receiver_ok);
}
- // Get the function to call from the stack.
- // +2 ~ receiver, return address
- __ mov(edi, Operand(esp, (argc_ + 2) * kPointerSize));
-
// Check that the function really is a JavaScript function.
__ JumpIfSmi(edi, &non_function);
// Goto slow case if we do not have a function.
}
-void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
+void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
// Register state for stub CallFunction (from CallFunctionStub in ic-ia32.cc).
// ----------- S t a t e -------------
- // No registers used on entry.
+ // -- edi: function
// -----------------------------------
- Generate_DebugBreakCallHelper(masm, 0, 0, false);
+ Generate_DebugBreakCallHelper(masm, edi.bit(), 0, false);
}
__ j(zero, &ok, Label::kNear);
// +1 for return address.
int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
+ __ mov(ecx, Operand(esp, receiver_offset));
+ __ JumpIfSmi(ecx, &ok);
+ __ CmpObjectType(ecx, JS_GLOBAL_PROXY_TYPE, ecx);
+ __ j(not_equal, &ok, Label::kNear);
__ mov(Operand(esp, receiver_offset),
Immediate(isolate()->factory()->undefined_value()));
__ bind(&ok);
flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
}
CallFunctionStub stub(arg_count, flags);
+ __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub, expr->id());
if (record_call_target) {
// There is a one element cache in the instruction stream.
// Record source position for debugger.
SetSourcePosition(expr->position());
CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
+ __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
}
VisitForAccumulatorValue(args->last()); // Function.
+ // Check for proxy.
+ Label proxy, done;
+ __ CmpObjectType(eax, JS_FUNCTION_PROXY_TYPE, ebx);
+ __ j(equal, &proxy);
+
// InvokeFunction requires the function in edi. Move it in there.
__ mov(edi, result_register());
ParameterCount count(arg_count);
__ InvokeFunction(edi, count, CALL_FUNCTION,
NullCallWrapper(), CALL_AS_METHOD);
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+ __ jmp(&done);
+
+ __ bind(&proxy);
+ __ push(eax);
+ __ CallRuntime(Runtime::kCall, args->length());
+ __ bind(&done);
+
context()->Plug(eax);
}
void LCodeGen::DoCallFunction(LCallFunction* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
+ ASSERT(ToRegister(instr->function()).is(edi));
ASSERT(ToRegister(instr->result()).is(eax));
int arity = instr->arity();
CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
- __ Drop(1);
}
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
LOperand* context = UseFixed(instr->context(), esi);
+ LOperand* function = UseFixed(instr->function(), edi);
argument_count_ -= instr->argument_count();
- LCallFunction* result = new(zone()) LCallFunction(context);
+ LCallFunction* result = new(zone()) LCallFunction(context, function);
return MarkAsCall(DefineFixed(result, eax), instr);
}
};
-class LCallFunction: public LTemplateInstruction<1, 1, 0> {
+class LCallFunction: public LTemplateInstruction<1, 2, 0> {
public:
- explicit LCallFunction(LOperand* context) {
+ explicit LCallFunction(LOperand* context, LOperand* function) {
inputs_[0] = context;
+ inputs_[1] = function;
}
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
DECLARE_HYDROGEN_ACCESSOR(CallFunction)
LOperand* context() { return inputs_[0]; }
- int arity() const { return hydrogen()->argument_count() - 2; }
+ LOperand* function() { return inputs_[1]; }
+ int arity() const { return hydrogen()->argument_count() - 1; }
};
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() >= 2);
+ CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
+ Object* receiver = args[0];
+ int argc = args.length() - 2;
+
+ // If there are too many arguments, allocate argv via malloc.
+ const int argv_small_size = 10;
+ Handle<Object> argv_small_buffer[argv_small_size];
+ SmartArrayPointer<Handle<Object> > argv_large_buffer;
+ Handle<Object>* argv = argv_small_buffer;
+ if (argc > argv_small_size) {
+ argv = new Handle<Object>[argc];
+ if (argv == NULL) return isolate->StackOverflow();
+ argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
+ }
+
+ for (int i = 0; i < argc; ++i) {
+ MaybeObject* maybe = args[1 + i];
+ Object* object;
+ if (!maybe->To<Object>(&object)) return maybe;
+ argv[i] = Handle<Object>(object);
+ }
+
+ bool threw;
+ Handle<JSReceiver> hfun(fun);
+ Handle<Object> hreceiver(receiver);
+ Handle<Object> result =
+ Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
+
+ if (threw) return Failure::Exception();
+ return *result;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
HandleScope scope(isolate);
ASSERT(args.length() == 5);
\
/* Utilities */ \
F(CheckIsBootstrapping, 0, 1) \
+ F(Call, -1 /* >= 2 */, 1) \
F(Apply, 5, 1) \
F(GetFunctionDelegate, 1, 1) \
F(GetConstructorDelegate, 1, 1) \
void CallFunctionStub::Generate(MacroAssembler* masm) {
+ // rdi : the function to call
Label slow, non_function;
// The receiver might implicitly be the global object. This is
__ bind(&call);
}
- // Get the function to call from the stack.
- // +2 ~ receiver, return address
- __ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize));
-
// Check that the function really is a JavaScript function.
__ JumpIfSmi(rdi, &non_function);
// Goto slow case if we do not have a function.
__ push(rcx);
__ Set(rax, argc_ + 1);
__ Set(rbx, 0);
- __ SetCallKind(rcx, CALL_AS_FUNCTION);
+ __ SetCallKind(rcx, CALL_AS_METHOD);
__ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
{
Handle<Code> adaptor =
}
-void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
+void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
// Register state for stub CallFunction (from CallFunctionStub in ic-x64.cc).
// ----------- S t a t e -------------
- // No registers used on entry.
+ // -- rdi : function
// -----------------------------------
- Generate_DebugBreakCallHelper(masm, 0, 0, false);
+ Generate_DebugBreakCallHelper(masm, rdi.bit(), 0, false);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
CallFunctionStub stub(arg_count, flags);
+ __ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
// Record source position for debugger.
SetSourcePosition(expr->position());
CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
+ __ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
}
VisitForAccumulatorValue(args->last()); // Function.
+ // Check for proxy.
+ Label proxy, done;
+ __ CmpObjectType(rax, JS_FUNCTION_PROXY_TYPE, rbx);
+ __ j(equal, &proxy);
+
// InvokeFunction requires the function in rdi. Move it in there.
__ movq(rdi, result_register());
ParameterCount count(arg_count);
__ InvokeFunction(rdi, count, CALL_FUNCTION,
NullCallWrapper(), CALL_AS_METHOD);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+ __ jmp(&done);
+
+ __ bind(&proxy);
+ __ push(rax);
+ __ CallRuntime(Runtime::kCall, args->length());
+ __ bind(&done);
+
context()->Plug(rax);
}
void LCodeGen::DoCallFunction(LCallFunction* instr) {
+ ASSERT(ToRegister(instr->function()).is(rdi));
ASSERT(ToRegister(instr->result()).is(rax));
int arity = instr->arity();
CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
- __ Drop(1);
}
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
+ LOperand* function = UseFixed(instr->function(), rdi);
argument_count_ -= instr->argument_count();
- LCallFunction* result = new LCallFunction();
+ LCallFunction* result = new LCallFunction(function);
return MarkAsCall(DefineFixed(result, rax), instr);
}
};
-class LCallFunction: public LTemplateInstruction<1, 0, 0> {
+class LCallFunction: public LTemplateInstruction<1, 1, 0> {
public:
- LCallFunction() {}
+ explicit LCallFunction(LOperand* function) {
+ inputs_[0] = function;
+ }
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
DECLARE_HYDROGEN_ACCESSOR(CallFunction)
- int arity() const { return hydrogen()->argument_count() - 2; }
+ LOperand* function() { return inputs_[0]; }
+ int arity() const { return hydrogen()->argument_count() - 1; }
};
"PromoteScheduledException": true,
"DeleteHandleScopeExtensions": true,
+ // Vararg with minimum number > 0.
+ "Call": true,
+
// Requires integer arguments to be non-negative.
"Apply": true,
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --harmony-proxies
+// Flags: --harmony-proxies --allow-natives-syntax
// Helper.
function TestCall(isStrict, callTrap) {
assertEquals(42, callTrap(5, 37))
- assertEquals(isStrict ? undefined : global_object, receiver)
+ assertSame(isStrict ? undefined : global_object, receiver)
var handler = {
get: function(r, k) {
}
}
var f = Proxy.createFunction(handler, callTrap)
+ var o = {f: f}
+ global_object.f = f
receiver = 333
assertEquals(42, f(11, 31))
- assertEquals(isStrict ? undefined : global_object, receiver)
- var o = {f: f}
+ assertSame(isStrict ? undefined : global_object, receiver)
receiver = 333
assertEquals(42, o.f(10, 32))
assertSame(o, receiver)
assertEquals(42, f.call(o, 32, 10))
assertSame(o, receiver)
receiver = 333
+ assertEquals(42, f.call(undefined, 33, 9))
+ assertSame(isStrict ? undefined : global_object, receiver)
+ receiver = 333
assertEquals(42, f.call(null, 33, 9))
assertSame(isStrict ? null : global_object, receiver)
receiver = 333
receiver = 333
assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, %Call(o, 11, 31, f))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, %Call(null, 11, 31, f))
+ assertSame(isStrict ? null : global_object, receiver)
+ receiver = 333
+ assertEquals(42, %Apply(f, o, [11, 31], 0, 2))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, %Apply(f, null, [11, 31], 0, 2))
+ assertSame(isStrict ? null : global_object, receiver)
+ receiver = 333
+ assertEquals(42, %_CallFunction(o, 11, 31, f))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, %_CallFunction(null, 11, 31, f))
+ assertSame(isStrict ? null : global_object, receiver)
var ff = Function.prototype.bind.call(f, o, 12)
assertTrue(ff.length <= 1) // TODO(rossberg): Not spec'ed yet, be lax.
assertEquals(42, ff(30))
assertSame(o, receiver)
receiver = 333
+ assertEquals(33, Function.prototype.call.call(ff, {}, 21))
+ assertSame(o, receiver)
+ receiver = 333
assertEquals(32, Function.prototype.apply.call(ff, {}, [20]))
assertSame(o, receiver)
+ receiver = 333
+ assertEquals(23, %Call({}, 11, ff))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(23, %Call({}, 11, 3, ff))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(24, %Apply(ff, {}, [12, 13], 0, 1))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(24, %Apply(ff, {}, [12, 13], 0, 2))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(34, %_CallFunction({}, 22, ff))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(34, %_CallFunction({}, 22, 3, ff))
+ assertSame(o, receiver)
var fff = Function.prototype.bind.call(ff, o, 30)
assertEquals(0, fff.length)
receiver = 333
assertEquals(42, Function.prototype.call.call(fff, {}))
assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, Function.prototype.apply.call(fff, {}))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, %Call({}, fff))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, %Call({}, 11, 3, fff))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, %Apply(fff, {}, [], 0, 0))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, %Apply(fff, {}, [12, 13], 0, 0))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, %Apply(fff, {}, [12, 13], 0, 2))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, %_CallFunction({}, fff))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, %_CallFunction({}, 3, 4, 5, fff))
+ assertSame(o, receiver)
var f = CreateFrozen({}, callTrap)
receiver = 333
assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
assertSame(o, receiver)
receiver = 333
- assertEquals(42, ff(30))
+ assertEquals(23, %Call({}, 11, 12, f))
assertSame(o, receiver)
receiver = 333
- assertEquals(32, Function.prototype.apply.call(ff, {}, [20]))
+ assertEquals(27, %Apply(f, {}, [12, 13, 14], 1, 2))
+ assertSame(o, receiver)
+ receiver = 333
+ assertEquals(42, %_CallFunction(o, 18, 24, f))
assertSame(o, receiver)
}
})
TestCall(false, function() {
- receiver = this; return arguments[0] + arguments[1]
+ receiver = this
+ return arguments[0] + arguments[1]
})
TestCall(false, Proxy.createFunction(handler, function(x, y) {
assertThrows(function(){ ({x: f})["x"](11) }, "myexn")
assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn")
assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn")
+ assertThrows(function(){ %Call({}, f) }, "myexn")
+ assertThrows(function(){ %Call({}, 1, 2, f) }, "myexn")
+ assertThrows(function(){ %Apply({}, f, [], 3, 0) }, "myexn")
+ assertThrows(function(){ %Apply({}, f, [3, 4], 0, 1) }, "myexn")
+ assertThrows(function(){ %_CallFunction({}, f) }, "myexn")
+ assertThrows(function(){ %_CallFunction({}, 1, 2, f) }, "myexn")
var f = CreateFrozen({}, callTrap)
assertThrows(function(){ f(11) }, "myexn")
assertThrows(function(){ ({x: f})["x"](11) }, "myexn")
assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn")
assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn")
+ assertThrows(function(){ %Call({}, f) }, "myexn")
+ assertThrows(function(){ %Call({}, 1, 2, f) }, "myexn")
+ assertThrows(function(){ %Apply({}, f, [], 3, 0) }, "myexn")
+ assertThrows(function(){ %Apply({}, f, [3, 4], 0, 1) }, "myexn")
+ assertThrows(function(){ %_CallFunction({}, f) }, "myexn")
+ assertThrows(function(){ %_CallFunction({}, 1, 2, f) }, "myexn")
}
TestCallThrow(function() { throw "myexn" })
CreateFrozen({}, function() { receiver = this; return 42 }),
CreateFrozen({}, function(x) { receiver = this; value = x })
)
+
+
+
+// TODO(rossberg): Ultimately, I want to have the following test function
+// run through, but it currently fails on so many cases (some not even
+// involving proxies), that I leave that for later...
+/*
+function TestCalls() {
+ var handler = {
+ get: function(r, k) {
+ return k == "length" ? 2 : Function.prototype[k]
+ }
+ }
+ var bind = Function.prototype.bind
+ var o = {}
+
+ var traps = [
+ function(x, y) {
+ return {receiver: this, result: x + y, strict: false}
+ },
+ function(x, y) { "use strict";
+ return {receiver: this, result: x + y, strict: true}
+ },
+ function() {
+ var x = arguments[0], y = arguments[1]
+ return {receiver: this, result: x + y, strict: false}
+ },
+ Proxy.createFunction(handler, function(x, y) {
+ return {receiver: this, result: x + y, strict: false}
+ }),
+ Proxy.createFunction(handler, function() {
+ var x = arguments[0], y = arguments[1]
+ return {receiver: this, result: x + y, strict: false}
+ }),
+ Proxy.createFunction(handler, function(x, y) { "use strict"
+ return {receiver: this, result: x + y, strict: true}
+ }),
+ CreateFrozen(handler, function(x, y) {
+ return {receiver: this, result: x + y, strict: false}
+ }),
+ CreateFrozen(handler, function(x, y) { "use strict"
+ return {receiver: this, result: x + y, strict: true}
+ }),
+ ]
+ var creates = [
+ function(trap) { return trap },
+ function(trap) { return CreateFrozen({}, callTrap) },
+ function(trap) { return Proxy.createFunction(handler, callTrap) },
+ function(trap) {
+ return Proxy.createFunction(handler, CreateFrozen({}, callTrap))
+ },
+ function(trap) {
+ return Proxy.createFunction(handler, Proxy.createFunction(handler, callTrap))
+ },
+ ]
+ var binds = [
+ function(f, o, x, y) { return f },
+ function(f, o, x, y) { return bind.call(f, o) },
+ function(f, o, x, y) { return bind.call(f, o, x) },
+ function(f, o, x, y) { return bind.call(f, o, x, y) },
+ function(f, o, x, y) { return bind.call(f, o, x, y, 5) },
+ function(f, o, x, y) { return bind.call(bind.call(f, o), {}, x, y) },
+ function(f, o, x, y) { return bind.call(bind.call(f, o, x), {}, y) },
+ function(f, o, x, y) { return bind.call(bind.call(f, o, x, y), {}, 5) },
+ ]
+ var calls = [
+ function(f, x, y) { return f(x, y) },
+ function(f, x, y) { var g = f; return g(x, y) },
+ function(f, x, y) { with ({}) return f(x, y) },
+ function(f, x, y) { var g = f; with ({}) return g(x, y) },
+ function(f, x, y, o) { with (o) return f(x, y) },
+ function(f, x, y, o) { return f.call(o, x, y) },
+ function(f, x, y, o) { return f.apply(o, [x, y]) },
+ function(f, x, y, o) { return Function.prototype.call.call(f, o, x, y) },
+ function(f, x, y, o) { return Function.prototype.apply.call(f, o, [x, y]) },
+ function(f, x, y, o) { return %_CallFunction(o, x, y, f) },
+ function(f, x, y, o) { return %Call(o, x, y, f) },
+ function(f, x, y, o) { return %Apply(f, o, [null, x, y, null], 1, 2) },
+ function(f, x, y, o) { return %Apply(f, o, arguments, 2, 2) },
+ function(f, x, y, o) { if (typeof o == "object") return o.f(x, y) },
+ function(f, x, y, o) { if (typeof o == "object") return o["f"](x, y) },
+ function(f, x, y, o) { if (typeof o == "object") return (1, o).f(x, y) },
+ function(f, x, y, o) { if (typeof o == "object") return (1, o)["f"](x, y) },
+ ]
+ var receivers = [o, global_object, undefined, null, 2, "bla", true]
+ var expectedNonStricts = [o, global_object, global_object, global_object]
+
+ for (var t = 0; t < traps.length; ++t) {
+ for (var i = 0; i < creates.length; ++i) {
+ for (var j = 0; j < binds.length; ++j) {
+ for (var k = 0; k < calls.length; ++k) {
+ for (var m = 0; m < receivers.length; ++m) {
+ for (var n = 0; n < receivers.length; ++n) {
+ var bound = receivers[m]
+ var receiver = receivers[n]
+ var func = binds[j](creates[i](traps[t]), bound, 31, 11)
+ var expected = j > 0 ? bound : receiver
+ var expectedNonStrict = expectedNonStricts[j > 0 ? m : n]
+ o.f = func
+ global_object.f = func
+ var x = calls[k](func, 11, 31, receiver)
+ if (x !== undefined) {
+ assertEquals(42, x.result)
+ if (calls[k].length < 4)
+ assertSame(x.strict ? undefined : global_object, x.receiver)
+ else if (x.strict)
+ assertSame(expected, x.receiver)
+ else if (expectedNonStrict === undefined)
+ assertSame(expected, x.receiver.valueOf())
+ else
+ assertSame(expectedNonStrict, x.receiver)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+TestCalls()
+*/