Commit b92ef0be authored by ager@chromium.org's avatar ager@chromium.org

MIPS: port Fix calls of strict mode function with an implicit receiver.

Port of r8040 to mips.

Original commit message:
Strict mode functions are to get 'undefined' as the receiver when
called with an implicit receiver. Modes are bad! It forces us to have
checks on all function calls.
This change attempts to limit the cost by passing information about
whether or not a call is with an implicit or explicit receiver in ecx
as part of the calling convention. The cost is setting ecx on all
calls and checking ecx on entry to strict mode functions.
Implicit/explicit receiver state has to be maintained by ICs. Various
stubs have to not clobber ecx or save and restore it.
CallFunction stub needs to check if the receiver is implicit when it
doesn't know from the context.

BUG=
TEST=

Review URL: http://codereview.chromium.org/6992051
Patch from Paul Lind <plind44@gmail.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8050 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 2489594d
......@@ -645,6 +645,7 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// Set expected number of arguments to zero (not changing a0).
__ mov(a2, zero_reg);
__ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
__ SetCallKind(t1, CALL_AS_METHOD);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
}
......@@ -1102,6 +1103,8 @@ void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
// Preserve the function.
__ push(a1);
// Push call kind information.
__ push(t1);
// Push the function on the stack as the argument to the runtime function.
__ push(a1);
......@@ -1109,6 +1112,9 @@ void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
__ CallRuntime(Runtime::kLazyCompile, 1);
// Calculate the entry point.
__ addiu(t9, v0, Code::kHeaderSize - kHeapObjectTag);
// Restore call kind information.
__ pop(t1);
// Restore saved function.
__ pop(a1);
......@@ -1126,12 +1132,17 @@ void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
// Preserve the function.
__ push(a1);
// Push call kind information.
__ push(t1);
// Push the function on the stack as the argument to the runtime function.
__ push(a1);
__ CallRuntime(Runtime::kLazyRecompile, 1);
// Calculate the entry point.
__ Addu(t9, v0, Operand(Code::kHeaderSize - kHeapObjectTag));
// Restore call kind information.
__ pop(t1);
// Restore saved function.
__ pop(a1);
......@@ -1306,6 +1317,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ Branch(&function, ne, a1, Operand(zero_reg));
__ mov(a2, zero_reg); // expected arguments is 0 for CALL_NON_FUNCTION
__ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION);
__ SetCallKind(t1, CALL_AS_METHOD);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
__ bind(&function);
......@@ -1321,6 +1333,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
FieldMemOperand(a3, SharedFunctionInfo::kFormalParameterCountOffset));
__ sra(a2, a2, kSmiTagSize);
__ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
__ SetCallKind(t1, CALL_AS_METHOD);
// Check formal and actual parameter counts.
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET, ne, a2, Operand(a0));
......@@ -1500,6 +1513,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// -- a1: function (passed through to callee)
// -- a2: expected arguments count
// -- a3: callee code entry
// -- t1: call kind information
// -----------------------------------
Label invoke, dont_adapt_arguments;
......
......@@ -4655,34 +4655,22 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
void CallFunctionStub::Generate(MacroAssembler* masm) {
Label slow;
// If the receiver might be a value (string, number or boolean) check
// for this and box it if it is.
if (ReceiverMightBeValue()) {
// The receiver might implicitly be the global object. This is
// indicated by passing the hole as the receiver to the call
// function stub.
if (ReceiverMightBeImplicit()) {
Label call;
// Get the receiver from the stack.
// function, receiver [, arguments]
Label receiver_is_value, receiver_is_js_object;
__ lw(a1, MemOperand(sp, argc_ * kPointerSize));
// Check if receiver is a smi (which is a number value).
__ JumpIfSmi(a1, &receiver_is_value);
// Check if the receiver is a valid JS object.
__ GetObjectType(a1, a2, a2);
__ Branch(&receiver_is_js_object,
ge,
a2,
Operand(FIRST_JS_OBJECT_TYPE));
// Call the runtime to box the value.
__ bind(&receiver_is_value);
// We need natives to execute this.
__ EnterInternalFrame();
__ push(a1);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
__ LeaveInternalFrame();
__ sw(v0, MemOperand(sp, argc_ * kPointerSize));
__ bind(&receiver_is_js_object);
__ lw(t0, MemOperand(sp, argc_ * kPointerSize));
// Call as function is indicated with the hole.
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
__ Branch(&call, ne, t0, Operand(at));
// Patch the receiver on the stack with the global receiver object.
__ lw(a1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ lw(a1, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset));
__ sw(a1, MemOperand(sp, argc_ * kPointerSize));
__ bind(&call);
}
// Get the function to call from the stack.
......@@ -4699,7 +4687,19 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
// Fast-case: Invoke the function now.
// a1: pushed function
ParameterCount actual(argc_);
__ InvokeFunction(a1, actual, JUMP_FUNCTION);
if (ReceiverMightBeImplicit()) {
Label call_as_function;
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
__ Branch(&call_as_function, eq, t0, Operand(at));
__ InvokeFunction(a1, actual, JUMP_FUNCTION);
__ bind(&call_as_function);
}
__ InvokeFunction(a1,
actual,
JUMP_FUNCTION,
NullCallWrapper(),
CALL_AS_FUNCTION);
// Slow-case: Non-function called.
__ bind(&slow);
......
......@@ -147,6 +147,19 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
}
#endif
// Strict mode functions need to replace the receiver with undefined
// when called as functions (without an explicit receiver
// object). t1 is zero for method calls and non-zero for function
// calls.
if (info->is_strict_mode()) {
Label ok;
__ Branch(&ok, eq, t1, Operand(zero_reg));
int receiver_offset = scope()->num_parameters() * kPointerSize;
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ sw(a2, MemOperand(sp, receiver_offset));
__ bind(&ok);
}
int locals_count = scope()->num_stack_slots();
__ Push(ra, fp, cp, a1);
......@@ -2105,7 +2118,7 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic =
isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop);
isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
EmitCallIC(ic, mode, expr->id());
RecordJSReturnSite(expr);
// Restore context register.
......@@ -2115,8 +2128,7 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Expression* key,
RelocInfo::Mode mode) {
Expression* key) {
// Load the key.
VisitForAccumulatorValue(key);
......@@ -2141,7 +2153,7 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Handle<Code> ic =
isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
__ lw(a2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
EmitCallIC(ic, mode, expr->id());
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
RecordJSReturnSite(expr);
// Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
......@@ -2255,7 +2267,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
// Record source position for debugger.
SetSourcePosition(expr->position());
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
......@@ -2305,9 +2317,10 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ bind(&call);
}
// The receiver is either the global receiver or a JSObject found by
// LoadContextSlot.
EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
// The receiver is either the global receiver or an object found
// by LoadContextSlot. That object could be the hole if the
// receiver is implicitly the global object.
EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
} else if (fun->AsProperty() != NULL) {
// Call to an object property.
Property* prop = fun->AsProperty();
......@@ -2348,7 +2361,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
{ PreservePositionScope scope(masm()->positions_recorder());
VisitForStackValue(prop->obj());
}
EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
EmitKeyedCallWithIC(expr, prop->key());
}
}
} else {
......@@ -3663,9 +3676,12 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
if (expr->is_jsruntime()) {
// Call the JS runtime function.
__ li(a2, Operand(expr->name()));
RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
Handle<Code> ic =
isolate()->stub_cache()->ComputeCallInitialize(arg_count, NOT_IN_LOOP);
EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id());
isolate()->stub_cache()->ComputeCallInitialize(arg_count,
NOT_IN_LOOP,
mode);
EmitCallIC(ic, mode, expr->id());
// Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
} else {
......
......@@ -494,7 +494,8 @@ Object* CallIC_Miss(Arguments args);
// The generated code falls through if both probes miss.
static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
int argc,
Code::Kind kind) {
Code::Kind kind,
Code::ExtraICState extra_ic_state) {
// ----------- S t a t e -------------
// -- a1 : receiver
// -- a2 : name
......@@ -505,7 +506,7 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
Code::Flags flags = Code::ComputeFlags(kind,
NOT_IN_LOOP,
MONOMORPHIC,
Code::kNoExtraICState,
extra_ic_state,
NORMAL,
argc);
Isolate::Current()->stub_cache()->GenerateProbe(
......@@ -593,7 +594,10 @@ static void GenerateCallNormal(MacroAssembler* masm, int argc) {
}
static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
static void GenerateCallMiss(MacroAssembler* masm,
int argc,
IC::UtilityId id,
Code::ExtraICState extra_ic_state) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
......@@ -643,22 +647,33 @@ static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
__ bind(&invoke);
}
// Invoke the function.
CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
ParameterCount actual(argc);
__ InvokeFunction(a1, actual, JUMP_FUNCTION);
__ InvokeFunction(a1,
actual,
JUMP_FUNCTION,
NullCallWrapper(),
call_kind);
}
void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
void CallIC::GenerateMiss(MacroAssembler* masm,
int argc,
Code::ExtraICState extra_ic_state) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
// -----------------------------------
GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
GenerateCallMiss(masm, argc, IC::kCallIC_Miss, extra_ic_state);
}
void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
void CallIC::GenerateMegamorphic(MacroAssembler* masm,
int argc,
Code::ExtraICState extra_ic_state) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
......@@ -666,8 +681,8 @@ void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
// Get the receiver of the function from the stack into a1.
__ lw(a1, MemOperand(sp, argc * kPointerSize));
GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
GenerateMiss(masm, argc);
GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
GenerateMiss(masm, argc, extra_ic_state);
}
......@@ -678,7 +693,7 @@ void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
// -----------------------------------
GenerateCallNormal(masm, argc);
GenerateMiss(masm, argc);
GenerateMiss(masm, argc, Code::kNoExtraICState);
}
......@@ -688,7 +703,7 @@ void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
// -- ra : return address
// -----------------------------------
GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState);
}
......@@ -773,7 +788,10 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
__ bind(&lookup_monomorphic_cache);
__ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, a0, a3);
GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
GenerateMonomorphicCacheProbe(masm,
argc,
Code::KEYED_CALL_IC,
Code::kNoExtraICState);
// Fall through on miss.
__ bind(&slow_call);
......
......@@ -2699,6 +2699,21 @@ void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg,
}
}
void MacroAssembler::SetCallKind(Register dst, CallKind call_kind) {
// This macro takes the dst register to make the code more readable
// at the call sites. However, the dst register has to be t1 to
// follow the calling convention which requires the call type to be
// in t1.
ASSERT(dst.is(t1));
if (call_kind == CALL_AS_FUNCTION) {
li(dst, Operand(Smi::FromInt(1)));
} else {
li(dst, Operand(Smi::FromInt(0)));
}
}
// -----------------------------------------------------------------------------
// JavaScript invokes.
......@@ -2708,7 +2723,8 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
Register code_reg,
Label* done,
InvokeFlag flag,
const CallWrapper& call_wrapper) {
const CallWrapper& call_wrapper,
CallKind call_kind) {
bool definitely_matches = false;
Label regular_invoke;
......@@ -2760,10 +2776,12 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
isolate()->builtins()->ArgumentsAdaptorTrampoline();
if (flag == CALL_FUNCTION) {
call_wrapper.BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET));
SetCallKind(t1, call_kind);
Call(adaptor, RelocInfo::CODE_TARGET);
call_wrapper.AfterCall();
jmp(done);
} else {
SetCallKind(t1, call_kind);
Jump(adaptor, RelocInfo::CODE_TARGET);
}
bind(&regular_invoke);
......@@ -2775,15 +2793,18 @@ void MacroAssembler::InvokeCode(Register code,
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper) {
const CallWrapper& call_wrapper,
CallKind call_kind) {
Label done;
InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag,
call_wrapper);
call_wrapper, call_kind);
if (flag == CALL_FUNCTION) {
SetCallKind(t1, call_kind);
Call(code);
} else {
ASSERT(flag == JUMP_FUNCTION);
SetCallKind(t1, call_kind);
Jump(code);
}
// Continue here if InvokePrologue does handle the invocation due to
......@@ -2796,13 +2817,17 @@ void MacroAssembler::InvokeCode(Handle<Code> code,
const ParameterCount& expected,
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag) {
InvokeFlag flag,
CallKind call_kind) {
Label done;
InvokePrologue(expected, actual, code, no_reg, &done, flag);
InvokePrologue(expected, actual, code, no_reg, &done, flag,
NullCallWrapper(), call_kind);
if (flag == CALL_FUNCTION) {
SetCallKind(t1, call_kind);
Call(code, rmode);
} else {
SetCallKind(t1, call_kind);
Jump(code, rmode);
}
// Continue here if InvokePrologue does handle the invocation due to
......@@ -2814,7 +2839,8 @@ void MacroAssembler::InvokeCode(Handle<Code> code,
void MacroAssembler::InvokeFunction(Register function,
const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper) {
const CallWrapper& call_wrapper,
CallKind call_kind) {
// Contract with called JS functions requires that function is passed in a1.
ASSERT(function.is(a1));
Register expected_reg = a2;
......@@ -2829,7 +2855,7 @@ void MacroAssembler::InvokeFunction(Register function,
lw(code_reg, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
ParameterCount expected(expected_reg);
InvokeCode(code_reg, expected, actual, flag, call_wrapper);
InvokeCode(code_reg, expected, actual, flag, call_wrapper, call_kind);
}
......
......@@ -614,25 +614,33 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
// -------------------------------------------------------------------------
// JavaScript invokes.
// Setup call kind marking in t1. The method takes t1 as an
// explicit first parameter to make the code more readable at the
// call sites.
void SetCallKind(Register dst, CallKind kind);
// Invoke the JavaScript function code by either calling or jumping.
void InvokeCode(Register code,
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper = NullCallWrapper());
const CallWrapper& call_wrapper = NullCallWrapper(),
CallKind call_kind = CALL_AS_METHOD);
void InvokeCode(Handle<Code> code,
const ParameterCount& expected,
const ParameterCount& actual,
RelocInfo::Mode rmode,
InvokeFlag flag);
InvokeFlag flag,
CallKind call_kind = CALL_AS_METHOD);
// Invoke the JavaScript function in the given register. Changes the
// current context to the context in the function before invoking.
void InvokeFunction(Register function,
const ParameterCount& actual,
InvokeFlag flag,
const CallWrapper& call_wrapper = NullCallWrapper());
const CallWrapper& call_wrapper = NullCallWrapper(),
CallKind call_kind = CALL_AS_METHOD);
void InvokeFunction(JSFunction* function,
const ParameterCount& actual,
......@@ -1098,7 +1106,8 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
Register code_reg,
Label* done,
InvokeFlag flag,
const CallWrapper& call_wrapper = NullCallWrapper());
const CallWrapper& call_wrapper = NullCallWrapper(),
CallKind call_kind = CALL_AS_METHOD);
// Get the code for the given builtin. Returns if able to resolve
// the function in the 'resolved' flag.
......
......@@ -1469,8 +1469,10 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
MaybeObject* CallStubCompiler::GenerateMissBranch() {
MaybeObject* maybe_obj = masm()->isolate()->stub_cache()->ComputeCallMiss(
arguments().immediate(), kind_);
MaybeObject* maybe_obj =
isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
kind_,
extra_ic_state_);
Object* obj;
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
__ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
......@@ -1789,7 +1791,9 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
Label* index_out_of_range_label = &index_out_of_range;
if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
if (kind_ == Code::CALL_IC &&
(CallICBase::StringStubState::decode(extra_ic_state_) ==
DEFAULT_STRING_STUB)) {
index_out_of_range_label = &miss;
}
......@@ -1873,7 +1877,9 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
Label index_out_of_range;
Label* index_out_of_range_label = &index_out_of_range;
if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
if (kind_ == Code::CALL_IC &&
(CallICBase::StringStubState::decode(extra_ic_state_) ==
DEFAULT_STRING_STUB)) {
index_out_of_range_label = &miss;
}
......@@ -2485,11 +2491,13 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
}
MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
MaybeObject* CallStubCompiler::CompileCallGlobal(
JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name,
Code::ExtraICState extra_ic_state) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
......@@ -2530,11 +2538,14 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
ASSERT(function->is_compiled());
Handle<Code> code(function->code());
ParameterCount expected(function->shared()->formal_parameter_count());
CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
if (V8::UseCrankshaft()) {
UNIMPLEMENTED_MIPS();
} else {
__ InvokeCode(code, expected, arguments(),
RelocInfo::CODE_TARGET, JUMP_FUNCTION);
__ InvokeCode(code, expected, arguments(), RelocInfo::CODE_TARGET,
JUMP_FUNCTION, call_kind);
}
// Handle call cache miss.
......
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