Revision: 8050
Author: [email protected]
Date: Tue May 24 23:04:01 2011
Log: 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 <[email protected]>.
http://code.google.com/p/v8/source/detail?r=8050
Modified:
/branches/bleeding_edge/src/mips/builtins-mips.cc
/branches/bleeding_edge/src/mips/code-stubs-mips.cc
/branches/bleeding_edge/src/mips/full-codegen-mips.cc
/branches/bleeding_edge/src/mips/ic-mips.cc
/branches/bleeding_edge/src/mips/macro-assembler-mips.cc
/branches/bleeding_edge/src/mips/macro-assembler-mips.h
/branches/bleeding_edge/src/mips/stub-cache-mips.cc
=======================================
--- /branches/bleeding_edge/src/mips/builtins-mips.cc Mon May 23 08:17:10
2011
+++ /branches/bleeding_edge/src/mips/builtins-mips.cc Tue May 24 23:04:01
2011
@@ -645,6 +645,7 @@
// 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 @@
// 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 @@
__ 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 @@
// 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 @@
__ 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 @@
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 @@
// -- a1: function (passed through to callee)
// -- a2: expected arguments count
// -- a3: callee code entry
+ // -- t1: call kind information
// -----------------------------------
Label invoke, dont_adapt_arguments;
=======================================
--- /branches/bleeding_edge/src/mips/code-stubs-mips.cc Tue May 24 05:20:16
2011
+++ /branches/bleeding_edge/src/mips/code-stubs-mips.cc Tue May 24 23:04:01
2011
@@ -4655,34 +4655,22 @@
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 @@
// 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);
=======================================
--- /branches/bleeding_edge/src/mips/full-codegen-mips.cc Tue May 24
08:11:48 2011
+++ /branches/bleeding_edge/src/mips/full-codegen-mips.cc Tue May 24
23:04:01 2011
@@ -146,6 +146,19 @@
__ stop("stop-at");
}
#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();
@@ -2105,7 +2118,7 @@
// 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::EmitKeyedCallWithIC(Call* expr,
- Expression* key,
- RelocInfo::Mode mode) {
+ Expression* key) {
// Load the key.
VisitForAccumulatorValue(key);
@@ -2141,7 +2153,7 @@
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 @@
// 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 @@
__ 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 @@
{ PreservePositionScope scope(masm()->positions_recorder());
VisitForStackValue(prop->obj());
}
- EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
+ EmitKeyedCallWithIC(expr, prop->key());
}
}
} else {
@@ -3663,9 +3676,12 @@
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 {
=======================================
--- /branches/bleeding_edge/src/mips/ic-mips.cc Mon May 23 00:12:58 2011
+++ /branches/bleeding_edge/src/mips/ic-mips.cc Tue May 24 23:04:01 2011
@@ -494,7 +494,8 @@
// 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 @@
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 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 @@
__ 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 @@
// 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 @@
// -----------------------------------
GenerateCallNormal(masm, argc);
- GenerateMiss(masm, argc);
+ GenerateMiss(masm, argc, Code::kNoExtraICState);
}
@@ -688,7 +703,7 @@
// -- ra : return address
// -----------------------------------
- GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
+ GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss,
Code::kNoExtraICState);
}
@@ -773,7 +788,10 @@
__ 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);
=======================================
--- /branches/bleeding_edge/src/mips/macro-assembler-mips.cc Tue May 24
00:23:32 2011
+++ /branches/bleeding_edge/src/mips/macro-assembler-mips.cc Tue May 24
23:04:01 2011
@@ -2698,6 +2698,21 @@
Move(a0, a1, 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 @@
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 @@
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(®ular_invoke);
@@ -2775,15 +2793,18 @@
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 @@
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::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 @@
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);
}
=======================================
--- /branches/bleeding_edge/src/mips/macro-assembler-mips.h Tue May 24
00:23:32 2011
+++ /branches/bleeding_edge/src/mips/macro-assembler-mips.h Tue May 24
23:04:01 2011
@@ -614,25 +614,33 @@
//
-------------------------------------------------------------------------
// 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 @@
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.
=======================================
--- /branches/bleeding_edge/src/mips/stub-cache-mips.cc Tue May 24 00:23:32
2011
+++ /branches/bleeding_edge/src/mips/stub-cache-mips.cc Tue May 24 23:04:01
2011
@@ -1469,8 +1469,10 @@
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 @@
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 @@
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::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 @@
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.
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev