MIPS: Handlify CompileConstructStub and the remaining CallStubCompiler functions.

Port r9837 (38061af).
Port r9834 (95ac04).

Original commit message (r9834):
Also, handlify functions for loading with interceptors and callbacks.
Remove some unneeded code.  Rename Foreign::address() because it
confusingly shadows HeapObject::address() which does something quite
different.

BUG=
TEST=

Review URL: http://codereview.chromium.org/8400087
Patch from Gergely Kis <gergely@homejinni.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9844 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 3ba06319
......@@ -5351,7 +5351,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
void StringCharCodeAtGenerator::GenerateSlow(
MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
MacroAssembler* masm,
const RuntimeCallHelper& call_helper) {
__ Abort("Unexpected fallthrough to CharCodeAt slow case");
// Index is not a smi.
......@@ -5437,7 +5438,8 @@ void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
void StringCharFromCodeGenerator::GenerateSlow(
MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
MacroAssembler* masm,
const RuntimeCallHelper& call_helper) {
__ Abort("Unexpected fallthrough to CharFromCode slow case");
__ bind(&slow_case_);
......@@ -5463,7 +5465,8 @@ void StringCharAtGenerator::GenerateFast(MacroAssembler* masm) {
void StringCharAtGenerator::GenerateSlow(
MacroAssembler* masm, const RuntimeCallHelper& call_helper) {
MacroAssembler* masm,
const RuntimeCallHelper& call_helper) {
char_code_at_generator_.GenerateSlow(masm, call_helper);
char_from_code_generator_.GenerateSlow(masm, call_helper);
}
......@@ -7021,86 +7024,6 @@ void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
}
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MaybeObject* StringDictionaryLookupStub::TryGenerateNegativeLookup(
MacroAssembler* masm,
Label* miss,
Label* done,
Register receiver,
Register properties,
String* name,
Register scratch0) {
// If names of slots in range from 1 to kProbes - 1 for the hash value are
// not equal to the name and kProbes-th slot is not used (its name is the
// undefined value), it guarantees the hash table doesn't contain the
// property. It's true even if some slots represent deleted properties
// (their names are the null value).
for (int i = 0; i < kInlinedProbes; i++) {
// scratch0 points to properties hash.
// Compute the masked index: (hash + i + i * i) & mask.
Register index = scratch0;
// Capacity is smi 2^n.
__ lw(index, FieldMemOperand(properties, kCapacityOffset));
__ Subu(index, index, Operand(1));
__ And(index, index, Operand(
Smi::FromInt(name->Hash() + StringDictionary::GetProbeOffset(i))));
// Scale the index by multiplying by the entry size.
ASSERT(StringDictionary::kEntrySize == 3);
// index *= 3.
__ sll(at, index, 1);
__ Addu(index, index, at);
Register entity_name = scratch0;
// Having undefined at this place means the name is not contained.
ASSERT_EQ(kSmiTagSize, 1);
Register tmp = properties;
__ sll(scratch0, index, 1);
__ Addu(tmp, properties, scratch0);
__ lw(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
ASSERT(!tmp.is(entity_name));
__ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
__ Branch(done, eq, entity_name, Operand(tmp));
if (i != kInlinedProbes - 1) {
// Stop if found the property.
__ Branch(miss, eq, entity_name, Operand(Handle<String>(name)));
// Check if the entry name is not a symbol.
__ lw(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
__ lbu(entity_name,
FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
__ And(scratch0, entity_name, Operand(kIsSymbolMask));
__ Branch(miss, eq, scratch0, Operand(zero_reg));
// Restore the properties.
__ lw(properties,
FieldMemOperand(receiver, JSObject::kPropertiesOffset));
}
}
const int spill_mask =
(ra.bit() | t2.bit() | t1.bit() | t0.bit() | a3.bit() |
a2.bit() | a1.bit() | a0.bit() | v0.bit());
__ MultiPush(spill_mask);
__ lw(a0, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
__ li(a1, Operand(Handle<String>(name)));
StringDictionaryLookupStub stub(NEGATIVE_LOOKUP);
MaybeObject* result = masm->TryCallStub(&stub);
if (result->IsFailure()) return result;
__ mov(at, v0);
__ MultiPop(spill_mask);
__ Branch(done, eq, at, Operand(zero_reg));
__ Branch(miss, ne, at, Operand(zero_reg));
return result;
}
// Probe the string dictionary in the |elements| register. Jump to the
// |done| label if a property with the given name is found. Jump to
// the |miss| label otherwise.
......
......@@ -807,17 +807,6 @@ class StringDictionaryLookupStub: public CodeStub {
Handle<String> name,
Register scratch0);
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MUST_USE_RESULT static MaybeObject* TryGenerateNegativeLookup(
MacroAssembler* masm,
Label* miss,
Label* done,
Register receiver,
Register properties,
String* name,
Register scratch0);
static void GeneratePositiveLookup(MacroAssembler* masm,
Label* miss,
Label* done,
......
......@@ -3610,7 +3610,7 @@ void MacroAssembler::InvokeFunction(Register function,
}
void MacroAssembler::InvokeFunction(JSFunction* function,
void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
const ParameterCount& actual,
InvokeFlag flag,
CallKind call_kind) {
......@@ -3618,7 +3618,7 @@ void MacroAssembler::InvokeFunction(JSFunction* function,
ASSERT(flag == JUMP_FUNCTION || has_frame());
// Get the function and setup the context.
li(a1, Operand(Handle<JSFunction>(function)));
li(a1, Operand(function));
lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
ParameterCount expected(function->shared()->formal_parameter_count());
......@@ -3739,45 +3739,19 @@ void MacroAssembler::CallStub(CodeStub* stub, Condition cond,
}
MaybeObject* MacroAssembler::TryCallStub(CodeStub* stub, Condition cond,
Register r1, const Operand& r2) {
ASSERT(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs.
Object* result;
{ MaybeObject* maybe_result = stub->TryGetCode();
if (!maybe_result->ToObject(&result)) return maybe_result;
}
Call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET,
kNoASTId, cond, r1, r2);
return result;
}
void MacroAssembler::TailCallStub(CodeStub* stub) {
ASSERT(allow_stub_calls_ || stub->CompilingCallsToThisStubIsGCSafe());
Jump(stub->GetCode(), RelocInfo::CODE_TARGET);
}
MaybeObject* MacroAssembler::TryTailCallStub(CodeStub* stub,
Condition cond,
Register r1,
const Operand& r2) {
Object* result;
{ MaybeObject* maybe_result = stub->TryGetCode();
if (!maybe_result->ToObject(&result)) return maybe_result;
}
Jump(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET, cond, r1, r2);
return result;
}
static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
return ref0.address() - ref1.address();
}
MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
ExternalReference function, int stack_space) {
void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function,
int stack_space) {
ExternalReference next_address =
ExternalReference::handle_scope_next_address();
const int kNextOffset = 0;
......@@ -3848,11 +3822,10 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
Ret();
bind(&promote_scheduled_exception);
MaybeObject* result = TryTailCallExternalReference(
ExternalReference(Runtime::kPromoteScheduledException, isolate()), 0, 1);
if (result->IsFailure()) {
return result;
}
TailCallExternalReference(
ExternalReference(Runtime::kPromoteScheduledException, isolate()),
0,
1);
// HandleScope limit has changed. Delete allocated extensions.
bind(&delete_allocated_handles);
......@@ -3865,8 +3838,6 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
1);
mov(v0, s0);
jmp(&leave_exit_frame);
return result;
}
......@@ -4089,17 +4060,6 @@ void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
}
MaybeObject* MacroAssembler::TryTailCallExternalReference(
const ExternalReference& ext, int num_arguments, int result_size) {
// TODO(1236192): Most runtime routines don't need the number of
// arguments passed in because it is constant. At some point we
// should remove this need and make the runtime routine entry code
// smarter.
li(a0, num_arguments);
return TryJumpToExternalReference(ext);
}
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
int num_arguments,
int result_size) {
......@@ -4116,14 +4076,6 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
}
MaybeObject* MacroAssembler::TryJumpToExternalReference(
const ExternalReference& builtin) {
li(a1, Operand(builtin));
CEntryStub stub(1);
return TryTailCallStub(&stub);
}
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag,
const CallWrapper& call_wrapper) {
......
......@@ -812,7 +812,7 @@ class MacroAssembler: public Assembler {
const CallWrapper& call_wrapper,
CallKind call_kind);
void InvokeFunction(JSFunction* function,
void InvokeFunction(Handle<JSFunction> function,
const ParameterCount& actual,
InvokeFlag flag,
CallKind call_kind);
......@@ -1042,27 +1042,9 @@ class MacroAssembler: public Assembler {
void CallStub(CodeStub* stub, Condition cond = cc_always,
Register r1 = zero_reg, const Operand& r2 = Operand(zero_reg));
// Call a code stub and return the code object called. Try to generate
// the code if necessary. Do not perform a GC but instead return a retry
// after GC failure.
MUST_USE_RESULT MaybeObject* TryCallStub(CodeStub* stub,
Condition cond = cc_always,
Register r1 = zero_reg,
const Operand& r2 =
Operand(zero_reg));
// Tail call a code stub (jump).
void TailCallStub(CodeStub* stub);
// Tail call a code stub (jump) and return the code object called. Try to
// generate the code if necessary. Do not perform a GC but instead return
// a retry after GC failure.
MUST_USE_RESULT MaybeObject* TryTailCallStub(CodeStub* stub,
Condition cond = cc_always,
Register r1 = zero_reg,
const Operand& r2 =
Operand(zero_reg));
void CallJSExitStub(CodeStub* stub);
// Call a runtime routine.
......@@ -1083,12 +1065,6 @@ class MacroAssembler: public Assembler {
int num_arguments,
int result_size);
// Tail call of a runtime routine (jump). Try to generate the code if
// necessary. Do not perform a GC but instead return a retry after GC
// failure.
MUST_USE_RESULT MaybeObject* TryTailCallExternalReference(
const ExternalReference& ext, int num_arguments, int result_size);
// Convenience function: tail call a runtime routine (jump).
void TailCallRuntime(Runtime::FunctionId fid,
int num_arguments,
......@@ -1140,15 +1116,14 @@ class MacroAssembler: public Assembler {
void SetCallCDoubleArguments(DoubleRegister dreg, Register reg);
// Calls an API function. Allocates HandleScope, extracts returned value
// from handle and propagates exceptions. Restores context.
MaybeObject* TryCallApiFunctionAndReturn(ExternalReference function,
int stack_space);
// from handle and propagates exceptions. Restores context. stack_space
// - space to be unwound on exit (includes the call js arguments space and
// the additional space allocated for the fast call).
void CallApiFunctionAndReturn(ExternalReference function, int stack_space);
// Jump to the builtin routine.
void JumpToExternalReference(const ExternalReference& builtin);
MaybeObject* TryJumpToExternalReference(const ExternalReference& ext);
// Invoke specified builtin JavaScript function. Adds an entry to
// the unresolved list if the name does not resolve.
void InvokeBuiltin(Builtins::JavaScript id,
......
......@@ -151,66 +151,6 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
}
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MUST_USE_RESULT static MaybeObject* TryGenerateDictionaryNegativeLookup(
MacroAssembler* masm,
Label* miss_label,
Register receiver,
String* name,
Register scratch0,
Register scratch1) {
ASSERT(name->IsSymbol());
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
__ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
Label done;
const int kInterceptorOrAccessCheckNeededMask =
(1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
// Bail out if the receiver has a named interceptor or requires access checks.
Register map = scratch1;
__ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
__ And(at, scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
__ Branch(miss_label, ne, at, Operand(zero_reg));
// Check that receiver is a JSObject.
__ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
__ Branch(miss_label, lt, scratch0, Operand(FIRST_SPEC_OBJECT_TYPE));
// Load properties array.
Register properties = scratch0;
__ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
// Check that the properties array is a dictionary.
__ lw(map, FieldMemOperand(properties, HeapObject::kMapOffset));
Register tmp = properties;
__ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
__ Branch(miss_label, ne, map, Operand(tmp));
// Restore the temporarily used register.
__ lw(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
MaybeObject* result = StringDictionaryLookupStub::TryGenerateNegativeLookup(
masm,
miss_label,
&done,
receiver,
properties,
name,
scratch1);
if (result->IsFailure()) return result;
__ bind(&done);
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
return result;
}
void StubCache::GenerateProbe(MacroAssembler* masm,
Code::Flags flags,
Register receiver,
......@@ -294,7 +234,10 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
MacroAssembler* masm, int index, Register prototype, Label* miss) {
MacroAssembler* masm,
int index,
Register prototype,
Label* miss) {
Isolate* isolate = masm->isolate();
// Check we're still in the same context.
__ lw(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
......@@ -302,8 +245,8 @@ void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
__ li(at, isolate->global());
__ Branch(miss, ne, prototype, Operand(at));
// Get the global function with the given index.
JSFunction* function =
JSFunction::cast(isolate->global_context()->get(index));
Handle<JSFunction> function(
JSFunction::cast(isolate->global_context()->get(index)));
// Load its initial map. The global functions all have initial maps.
__ li(prototype, Handle<Map>(function->initial_map()));
// Load the prototype from the initial map.
......@@ -565,23 +508,24 @@ static void PushInterceptorArguments(MacroAssembler* masm,
Register receiver,
Register holder,
Register name,
JSObject* holder_obj) {
Handle<JSObject> holder_obj) {
__ push(name);
InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
ASSERT(!masm->isolate()->heap()->InNewSpace(interceptor));
Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
Register scratch = name;
__ li(scratch, Operand(Handle<Object>(interceptor)));
__ li(scratch, Operand(interceptor));
__ Push(scratch, receiver, holder);
__ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
__ push(scratch);
}
static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
static void CompileCallLoadPropertyWithInterceptor(
MacroAssembler* masm,
Register receiver,
Register holder,
Register name,
JSObject* holder_obj) {
Handle<JSObject> holder_obj) {
PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
ExternalReference ref =
......@@ -617,8 +561,7 @@ static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
}
static MaybeObject* GenerateFastApiDirectCall(
MacroAssembler* masm,
static void GenerateFastApiDirectCall(MacroAssembler* masm,
const CallOptimization& optimization,
int argc) {
// ----------- S t a t e -------------
......@@ -631,18 +574,18 @@ static MaybeObject* GenerateFastApiDirectCall(
// -- sp[(argc + 4) * 4] : receiver
// -----------------------------------
// Get the function and setup the context.
JSFunction* function = optimization.constant_function();
__ li(t1, Operand(Handle<JSFunction>(function)));
Handle<JSFunction> function = optimization.constant_function();
__ li(t1, Operand(function));
__ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
// Pass the additional arguments FastHandleApiCall expects.
Object* call_data = optimization.api_call_info()->data();
Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
if (masm->isolate()->heap()->InNewSpace(call_data)) {
__ li(a0, api_call_info_handle);
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> call_data(api_call_info->data());
if (masm->isolate()->heap()->InNewSpace(*call_data)) {
__ li(a0, api_call_info);
__ lw(t2, FieldMemOperand(a0, CallHandlerInfo::kDataOffset));
} else {
__ li(t2, Operand(Handle<Object>(call_data)));
__ li(t2, call_data);
}
// Store js function and call data.
......@@ -653,10 +596,6 @@ static MaybeObject* GenerateFastApiDirectCall(
// (refer to layout above).
__ Addu(a2, sp, Operand(2 * kPointerSize));
Object* callback = optimization.api_call_info()->callback();
Address api_function_address = v8::ToCData<Address>(callback);
ApiFunction fun(api_function_address);
const int kApiStackSpace = 4;
FrameScope frame_scope(masm, StackFrame::MANUAL);
......@@ -682,17 +621,15 @@ static MaybeObject* GenerateFastApiDirectCall(
// v8::Arguments::is_construct_call = 0
__ sw(zero_reg, MemOperand(a1, 3 * kPointerSize));
// Emitting a stub call may try to allocate (if the code is not
// already generated). Do not allow the assembler to perform a
// garbage collection but instead return the allocation failure
// object.
const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
ExternalReference ref =
ExternalReference(&fun,
ExternalReference::DIRECT_API_CALL,
masm->isolate());
AllowExternalCallThatCantCauseGC scope(masm);
return masm->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace);
__ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
}
class CallInterceptorCompiler BASE_EMBEDDED {
......@@ -706,10 +643,10 @@ class CallInterceptorCompiler BASE_EMBEDDED {
name_(name),
extra_ic_state_(extra_ic_state) {}
MaybeObject* Compile(MacroAssembler* masm,
JSObject* object,
JSObject* holder,
String* name,
void Compile(MacroAssembler* masm,
Handle<JSObject> object,
Handle<JSObject> holder,
Handle<String> name,
LookupResult* lookup,
Register receiver,
Register scratch1,
......@@ -721,67 +658,44 @@ class CallInterceptorCompiler BASE_EMBEDDED {
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, miss);
CallOptimization optimization(lookup);
if (optimization.is_constant_call()) {
return CompileCacheable(masm,
object,
receiver,
scratch1,
scratch2,
scratch3,
holder,
lookup,
name,
optimization,
miss);
CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
holder, lookup, name, optimization, miss);
} else {
CompileRegular(masm,
object,
receiver,
scratch1,
scratch2,
scratch3,
name,
holder,
miss);
return masm->isolate()->heap()->undefined_value();
CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
name, holder, miss);
}
}
private:
MaybeObject* CompileCacheable(MacroAssembler* masm,
JSObject* object,
void CompileCacheable(MacroAssembler* masm,
Handle<JSObject> object,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
JSObject* interceptor_holder,
Handle<JSObject> interceptor_holder,
LookupResult* lookup,
String* name,
Handle<String> name,
const CallOptimization& optimization,
Label* miss_label) {
ASSERT(optimization.is_constant_call());
ASSERT(!lookup->holder()->IsGlobalObject());
Counters* counters = masm->isolate()->counters();
int depth1 = kInvalidProtoDepth;
int depth2 = kInvalidProtoDepth;
bool can_do_fast_api_call = false;
if (optimization.is_simple_api_call() &&
!lookup->holder()->IsGlobalObject()) {
depth1 =
optimization.GetPrototypeDepthOfExpectedType(object,
interceptor_holder);
depth1 = optimization.GetPrototypeDepthOfExpectedType(
object, interceptor_holder);
if (depth1 == kInvalidProtoDepth) {
depth2 =
optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
lookup->holder());
depth2 = optimization.GetPrototypeDepthOfExpectedType(
interceptor_holder, Handle<JSObject>(lookup->holder()));
}
can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
(depth2 != kInvalidProtoDepth);
can_do_fast_api_call =
depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth;
}
__ IncrementCounter(counters->call_const_interceptor(), 1,
......@@ -798,9 +712,9 @@ class CallInterceptorCompiler BASE_EMBEDDED {
Label miss_cleanup;
Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
Register holder =
stub_compiler_->CheckPrototypes(object, receiver,
interceptor_holder, scratch1,
scratch2, scratch3, name, depth1, miss);
stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
scratch1, scratch2, scratch3,
name, depth1, miss);
// Invoke an interceptor and if it provides a value,
// branch to |regular_invoke|.
......@@ -813,10 +727,11 @@ class CallInterceptorCompiler BASE_EMBEDDED {
// Check that the maps from interceptor's holder to constant function's
// holder haven't changed and thus we can use cached constant function.
if (interceptor_holder != lookup->holder()) {
if (*interceptor_holder != lookup->holder()) {
stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
lookup->holder(), scratch1,
scratch2, scratch3, name, depth2, miss);
Handle<JSObject>(lookup->holder()),
scratch1, scratch2, scratch3,
name, depth2, miss);
} else {
// CheckPrototypes has a side effect of fetching a 'holder'
// for API (object which is instanceof for the signature). It's
......@@ -827,10 +742,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
// Invoke function.
if (can_do_fast_api_call) {
MaybeObject* result = GenerateFastApiDirectCall(masm,
optimization,
arguments_.immediate());
if (result->IsFailure()) return result;
GenerateFastApiDirectCall(masm, optimization, arguments_.immediate());
} else {
CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
? CALL_AS_FUNCTION
......@@ -851,68 +763,57 @@ class CallInterceptorCompiler BASE_EMBEDDED {
if (can_do_fast_api_call) {
FreeSpaceForFastApiCall(masm);
}
return masm->isolate()->heap()->undefined_value();
}
void CompileRegular(MacroAssembler* masm,
JSObject* object,
Handle<JSObject> object,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
String* name,
JSObject* interceptor_holder,
Handle<String> name,
Handle<JSObject> interceptor_holder,
Label* miss_label) {
Register holder =
stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
scratch1, scratch2, scratch3, name,
miss_label);
scratch1, scratch2, scratch3,
name, miss_label);
// Call a runtime function to load the interceptor property.
FrameScope scope(masm, StackFrame::INTERNAL);
// Save the name_ register across the call.
__ push(name_);
PushInterceptorArguments(masm,
receiver,
holder,
name_,
interceptor_holder);
PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
__ CallExternalReference(
ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
masm->isolate()),
5);
// Restore the name_ register.
__ pop(name_);
// Leave the internal frame.
}
void LoadWithInterceptor(MacroAssembler* masm,
Register receiver,
Register holder,
JSObject* holder_obj,
Handle<JSObject> holder_obj,
Register scratch,
Label* interceptor_succeeded) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(holder, name_);
CompileCallLoadPropertyWithInterceptor(masm,
receiver,
holder,
name_,
holder_obj);
__ pop(name_); // Restore the name.
__ pop(receiver); // Restore the holder.
}
// If interceptor returns no-result sentinel, call the constant function.
__ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
__ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
......@@ -945,29 +846,6 @@ static void GenerateCheckPropertyCell(MacroAssembler* masm,
}
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MUST_USE_RESULT static MaybeObject* TryGenerateCheckPropertyCell(
MacroAssembler* masm,
GlobalObject* global,
String* name,
Register scratch,
Label* miss) {
Object* probe;
{ MaybeObject* maybe_probe = global->EnsurePropertyCell(name);
if (!maybe_probe->ToObject(&probe)) return maybe_probe;
}
JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
ASSERT(cell->value()->IsTheHole());
__ li(scratch, Operand(Handle<Object>(cell)));
__ lw(scratch,
FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
__ Branch(miss, ne, scratch, Operand(at));
return cell;
}
// Calls GenerateCheckPropertyCell for each global object in the prototype chain
// from object to (but not including) holder.
static void GenerateCheckPropertyCells(MacroAssembler* masm,
......@@ -990,34 +868,6 @@ static void GenerateCheckPropertyCells(MacroAssembler* masm,
}
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MUST_USE_RESULT static MaybeObject* TryGenerateCheckPropertyCells(
MacroAssembler* masm,
JSObject* object,
JSObject* holder,
String* name,
Register scratch,
Label* miss) {
JSObject* current = object;
while (current != holder) {
if (current->IsGlobalObject()) {
// Returns a cell or a failure.
MaybeObject* result = TryGenerateCheckPropertyCell(
masm,
GlobalObject::cast(current),
name,
scratch,
miss);
if (result->IsFailure()) return result;
}
ASSERT(current->IsJSObject());
current = JSObject::cast(current->GetPrototype());
}
return NULL;
}
// Convert and store int passed in register ival to IEEE 754 single precision
// floating point value at memory location (dst + 4 * wordoffset)
// If FPU is available use it for conversion.
......@@ -1240,146 +1090,6 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
}
Register StubCompiler::CheckPrototypes(JSObject* object,
Register object_reg,
JSObject* holder,
Register holder_reg,
Register scratch1,
Register scratch2,
String* name,
int save_at_depth,
Label* miss) {
// Make sure there's no overlap between holder and object registers.
ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
&& !scratch2.is(scratch1));
// Keep track of the current object in register reg.
Register reg = object_reg;
int depth = 0;
if (save_at_depth == depth) {
__ sw(reg, MemOperand(sp));
}
// Check the maps in the prototype chain.
// Traverse the prototype chain from the object and do map checks.
JSObject* current = object;
while (current != holder) {
depth++;
// Only global objects and objects that do not require access
// checks are allowed in stubs.
ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
ASSERT(current->GetPrototype()->IsJSObject());
JSObject* prototype = JSObject::cast(current->GetPrototype());
if (!current->HasFastProperties() &&
!current->IsJSGlobalObject() &&
!current->IsJSGlobalProxy()) {
if (!name->IsSymbol()) {
MaybeObject* maybe_lookup_result = heap()->LookupSymbol(name);
Object* lookup_result = NULL; // Initialization to please compiler.
if (!maybe_lookup_result->ToObject(&lookup_result)) {
set_failure(Failure::cast(maybe_lookup_result));
return reg;
}
name = String::cast(lookup_result);
}
ASSERT(current->property_dictionary()->FindEntry(name) ==
StringDictionary::kNotFound);
MaybeObject* negative_lookup =
TryGenerateDictionaryNegativeLookup(masm(),
miss,
reg,
name,
scratch1,
scratch2);
if (negative_lookup->IsFailure()) {
set_failure(Failure::cast(negative_lookup));
return reg;
}
__ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
reg = holder_reg; // From now the object is in holder_reg.
__ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
} else if (heap()->InNewSpace(prototype)) {
// Get the map of the current object.
__ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
// Branch on the result of the map check.
__ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
// Check access rights to the global object. This has to happen
// after the map check so that we know that the object is
// actually a global object.
if (current->IsJSGlobalProxy()) {
__ CheckAccessGlobalProxy(reg, scratch1, miss);
// Restore scratch register to be the map of the object. In the
// new space case below, we load the prototype from the map in
// the scratch register.
__ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
}
reg = holder_reg; // From now the object is in holder_reg.
// The prototype is in new space; we cannot store a reference
// to it in the code. Load it from the map.
__ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
} else {
// Check the map of the current object.
__ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
// Branch on the result of the map check.
__ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
// Check access rights to the global object. This has to happen
// after the map check so that we know that the object is
// actually a global object.
if (current->IsJSGlobalProxy()) {
__ CheckAccessGlobalProxy(reg, scratch1, miss);
}
// The prototype is in old space; load it directly.
reg = holder_reg; // From now the object is in holder_reg.
__ li(reg, Operand(Handle<JSObject>(prototype)));
}
if (save_at_depth == depth) {
__ sw(reg, MemOperand(sp));
}
// Go to the next object in the prototype chain.
current = prototype;
}
// Check the holder map.
__ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
__ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
// Log the check depth.
LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
// Perform security check for access to the global object.
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
if (holder->IsJSGlobalProxy()) {
__ CheckAccessGlobalProxy(reg, scratch1, miss);
}
// If we've skipped any global objects, it's not enough to verify
// that their maps haven't changed. We also need to check that the
// property cell for the property is still empty.
MaybeObject* result = TryGenerateCheckPropertyCells(masm(),
object,
holder,
name,
scratch1,
miss);
if (result->IsFailure()) set_failure(Failure::cast(result));
// Return the register containing the holder.
return reg;
}
void StubCompiler::GenerateLoadField(Handle<JSObject> object,
Handle<JSObject> holder,
Register receiver,
......@@ -1424,49 +1134,43 @@ void StubCompiler::GenerateLoadConstant(Handle<JSObject> object,
}
MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
JSObject* holder,
void StubCompiler::GenerateLoadCallback(Handle<JSObject> object,
Handle<JSObject> holder,
Register receiver,
Register name_reg,
Register scratch1,
Register scratch2,
Register scratch3,
AccessorInfo* callback,
String* name,
Handle<AccessorInfo> callback,
Handle<String> name,
Label* miss) {
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, miss, scratch1);
// Check that the maps haven't changed.
Register reg =
CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3,
name, miss);
Register reg = CheckPrototypes(object, receiver, holder, scratch1,
scratch2, scratch3, name, miss);
// Build AccessorInfo::args_ list on the stack and push property name below
// the exit frame to make GC aware of them and store pointers to them.
__ push(receiver);
__ mov(scratch2, sp); // scratch2 = AccessorInfo::args_
Handle<AccessorInfo> callback_handle(callback);
if (heap()->InNewSpace(callback_handle->data())) {
__ li(scratch3, callback_handle);
if (heap()->InNewSpace(callback->data())) {
__ li(scratch3, callback);
__ lw(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset));
} else {
__ li(scratch3, Handle<Object>(callback_handle->data()));
__ li(scratch3, Handle<Object>(callback->data()));
}
__ Push(reg, scratch3, name_reg);
__ mov(a2, scratch2); // Saved in case scratch2 == a1.
__ mov(a1, sp); // a1 (first argument - see note below) = Handle<String>
Address getter_address = v8::ToCData<Address>(callback->getter());
ApiFunction fun(getter_address);
// NOTE: the O32 abi requires a0 to hold a special pointer when returning a
// struct from the function (which is currently the case). This means we pass
// the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn
// will handle setting up a0.
const int kApiStackSpace = 1;
FrameScope frame_scope(masm(), StackFrame::MANUAL);
__ EnterExitFrame(false, kApiStackSpace);
......@@ -1476,28 +1180,26 @@ MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
// a2 (second argument - see note above) = AccessorInfo&
__ Addu(a2, sp, kPointerSize);
// Emitting a stub call may try to allocate (if the code is not
// already generated). Do not allow the assembler to perform a
// garbage collection but instead return the allocation failure
// object.
const int kStackUnwindSpace = 4;
Address getter_address = v8::ToCData<Address>(callback->getter());
ApiFunction fun(getter_address);
ExternalReference ref =
ExternalReference(&fun,
ExternalReference::DIRECT_GETTER_CALL,
masm()->isolate());
// 4 args - will be freed later by LeaveExitFrame.
return masm()->TryCallApiFunctionAndReturn(ref, 4);
__ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
}
void StubCompiler::GenerateLoadInterceptor(JSObject* object,
JSObject* interceptor_holder,
void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object,
Handle<JSObject> interceptor_holder,
LookupResult* lookup,
Register receiver,
Register name_reg,
Register scratch1,
Register scratch2,
Register scratch3,
String* name,
Handle<String> name,
Label* miss) {
ASSERT(interceptor_holder->HasNamedInterceptor());
ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
......@@ -1513,9 +1215,9 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
if (lookup->type() == FIELD) {
compile_followup_inline = true;
} else if (lookup->type() == CALLBACKS &&
lookup->GetCallbackObject()->IsAccessorInfo() &&
AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) {
compile_followup_inline = true;
lookup->GetCallbackObject()->IsAccessorInfo()) {
compile_followup_inline =
AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL;
}
}
......@@ -1532,14 +1234,12 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
// Requires a frame to make GC aware of pushed pointers.
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
// CALLBACKS case needs a receiver to be passed into C++ callback.
__ Push(receiver, holder_reg, name_reg);
} else {
__ Push(holder_reg, name_reg);
}
// Invoke an interceptor. Note: map checks from receiver to
// interceptor's holder has been compiled before (see a caller
// of this method).
......@@ -1548,7 +1248,6 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
holder_reg,
name_reg,
interceptor_holder);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed;
......@@ -1563,16 +1262,14 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) {
__ pop(receiver);
}
// Leave the internal frame.
}
// Check that the maps from interceptor's holder to lookup's holder
// haven't changed. And load lookup's holder into |holder| register.
if (interceptor_holder != lookup->holder()) {
if (*interceptor_holder != lookup->holder()) {
holder_reg = CheckPrototypes(interceptor_holder,
holder_reg,
lookup->holder(),
Handle<JSObject>(lookup->holder()),
scratch1,
scratch2,
scratch3,
......@@ -1591,15 +1288,14 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object,
// We found CALLBACKS property in prototype chain of interceptor's
// holder.
ASSERT(lookup->type() == CALLBACKS);
ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject());
ASSERT(callback != NULL);
Handle<AccessorInfo> callback(
AccessorInfo::cast(lookup->GetCallbackObject()));
ASSERT(callback->getter() != NULL);
// Tail call to runtime.
// Important invariant in CALLBACKS case: the code above must be
// structured to never clobber |receiver| register.
__ li(scratch2, Handle<AccessorInfo>(callback));
__ li(scratch2, callback);
// holder_reg is either receiver or scratch1.
if (!receiver.is(holder_reg)) {
ASSERT(scratch1.is(holder_reg));
......@@ -1642,9 +1338,9 @@ void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
}
void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
JSObject* holder,
String* name,
void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
Handle<JSObject> holder,
Handle<String> name,
Label* miss) {
ASSERT(holder->IsGlobalObject());
......@@ -1657,7 +1353,7 @@ void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
// If the object is the holder then we know that it's a global
// object which can only happen for contextual calls. In this case,
// the receiver cannot be a smi.
if (object != holder) {
if (!object.is_identical_to(holder)) {
__ JumpIfSmi(a0, miss);
}
......@@ -1666,15 +1362,16 @@ void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object,
}
void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
JSFunction* function,
void CallStubCompiler::GenerateLoadFunctionFromCell(
Handle<JSGlobalPropertyCell> cell,
Handle<JSFunction> function,
Label* miss) {
// Get the value from the cell.
__ li(a3, Operand(Handle<JSGlobalPropertyCell>(cell)));
__ li(a3, Operand(cell));
__ lw(a1, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset));
// Check that the cell contains the same function.
if (heap()->InNewSpace(function)) {
if (heap()->InNewSpace(*function)) {
// We can't embed a pointer to a function in new space so we have
// to verify that the shared function info is unchanged. This has
// the nice side effect that multiple closures based on the same
......@@ -1689,7 +1386,7 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
__ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
__ Branch(miss, ne, t0, Operand(a3));
} else {
__ Branch(miss, ne, a1, Operand(Handle<JSFunction>(function)));
__ Branch(miss, ne, a1, Operand(function));
}
}
......@@ -1703,20 +1400,6 @@ void CallStubCompiler::GenerateMissBranch() {
}
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MaybeObject* CallStubCompiler::TryGenerateMissBranch() {
MaybeObject* maybe_obj =
isolate()->stub_cache()->TryComputeCallMiss(arguments().immediate(),
kind_,
extra_state_);
Object* obj;
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
__ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
return obj;
}
Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
Handle<JSObject> holder,
int index,
......@@ -1751,11 +1434,12 @@ Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
}
MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
Handle<Code> CallStubCompiler::CompileArrayPushCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<JSFunction> function,
Handle<String> name) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
......@@ -1765,11 +1449,11 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
// -----------------------------------
// If object is not an array, bail out to regular call.
if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
Label miss;
GenerateNameCheck(Handle<String>(name), &miss);
GenerateNameCheck(name, &miss);
Register receiver = a1;
......@@ -1781,8 +1465,8 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
__ JumpIfSmi(receiver, &miss);
// Check that the maps haven't changed.
CheckPrototypes(JSObject::cast(object), receiver,
holder, a3, v0, t0, name, &miss);
CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, a3, v0, t0,
name, &miss);
if (argc == 0) {
// Nothing to do, just return the length.
......@@ -1791,10 +1475,8 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
__ Ret();
} else {
Label call_builtin;
Register elements = a3;
Register end_elements = t1;
// Get the elements array of the object.
__ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
......@@ -1935,19 +1617,19 @@ MaybeObject* CallStubCompiler::CompileArrayPushCall(Object* object,
// Handle call cache miss.
__ bind(&miss);
MaybeObject* maybe_result = TryGenerateMissBranch();
if (maybe_result->IsFailure()) return maybe_result;
GenerateMissBranch();
// Return the generated code.
return TryGetCode(function);
return GetCode(function);
}
MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
Handle<Code> CallStubCompiler::CompileArrayPopCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<JSFunction> function,
Handle<String> name) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
......@@ -1957,25 +1639,22 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
// -----------------------------------
// If object is not an array, bail out to regular call.
if (!object->IsJSArray() || cell != NULL) return heap()->undefined_value();
if (!object->IsJSArray() || !cell.is_null()) return Handle<Code>::null();
Label miss, return_undefined, call_builtin;
Register receiver = a1;
Register elements = a3;
GenerateNameCheck(Handle<String>(name), &miss);
GenerateNameCheck(name, &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
__ lw(receiver, MemOperand(sp, argc * kPointerSize));
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, &miss);
// Check that the maps haven't changed.
CheckPrototypes(JSObject::cast(object),
receiver, holder, elements, t0, v0, name, &miss);
CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
t0, v0, name, &miss);
// Get the elements array of the object.
__ lw(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
......@@ -2024,20 +1703,19 @@ MaybeObject* CallStubCompiler::CompileArrayPopCall(Object* object,
// Handle call cache miss.
__ bind(&miss);
MaybeObject* maybe_result = TryGenerateMissBranch();
if (maybe_result->IsFailure()) return maybe_result;
GenerateMissBranch();
// Return the generated code.
return TryGetCode(function);
return GetCode(function);
}
MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<JSFunction> function,
Handle<String> name) {
// ----------- S t a t e -------------
// -- a2 : function name
// -- ra : return address
......@@ -2047,10 +1725,9 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
// -----------------------------------
// If object is not a string, bail out to regular call.
if (!object->IsString() || cell != NULL) return heap()->undefined_value();
if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
const int argc = arguments().immediate();
Label miss;
Label name_miss;
Label index_out_of_range;
......@@ -2063,16 +1740,16 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
index_out_of_range_label = &miss;
}
GenerateNameCheck(Handle<String>(name), &name_miss);
GenerateNameCheck(name, &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
Context::STRING_FUNCTION_INDEX,
v0,
&miss);
ASSERT(object != holder);
CheckPrototypes(JSObject::cast(object->GetPrototype()), v0, holder,
a1, a3, t0, name, &miss);
ASSERT(!object.is_identical_to(holder));
CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
v0, holder, a1, a3, t0, name, &miss);
Register receiver = a1;
Register index = t1;
......@@ -2085,7 +1762,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
__ LoadRoot(index, Heap::kUndefinedValueRootIndex);
}
StringCharCodeAtGenerator char_code_at_generator(receiver,
StringCharCodeAtGenerator generator(receiver,
index,
scratch,
result,
......@@ -2093,12 +1770,12 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
&miss, // When not a number.
index_out_of_range_label,
STRING_INDEX_IS_NUMBER);
char_code_at_generator.GenerateFast(masm());
generator.GenerateFast(masm());
__ Drop(argc + 1);
__ Ret();
StubRuntimeCallHelper call_helper;
char_code_at_generator.GenerateSlow(masm(), call_helper);
generator.GenerateSlow(masm(), call_helper);
if (index_out_of_range.is_linked()) {
__ bind(&index_out_of_range);
......@@ -2109,22 +1786,21 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
__ bind(&miss);
// Restore function name in a2.
__ li(a2, Handle<String>(name));
__ li(a2, name);
__ bind(&name_miss);
MaybeObject* maybe_result = TryGenerateMissBranch();
if (maybe_result->IsFailure()) return maybe_result;
GenerateMissBranch();
// Return the generated code.
return TryGetCode(function);
return GetCode(function);
}
MaybeObject* CallStubCompiler::CompileStringCharAtCall(
Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
Handle<Code> CallStubCompiler::CompileStringCharAtCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<JSFunction> function,
Handle<String> name) {
// ----------- S t a t e -------------
// -- a2 : function name
// -- ra : return address
......@@ -2134,31 +1810,28 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
// -----------------------------------
// If object is not a string, bail out to regular call.
if (!object->IsString() || cell != NULL) return heap()->undefined_value();
if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
const int argc = arguments().immediate();
Label miss;
Label name_miss;
Label index_out_of_range;
Label* index_out_of_range_label = &index_out_of_range;
if (kind_ == Code::CALL_IC &&
(CallICBase::StringStubState::decode(extra_state_) ==
DEFAULT_STRING_STUB)) {
index_out_of_range_label = &miss;
}
GenerateNameCheck(Handle<String>(name), &name_miss);
GenerateNameCheck(name, &name_miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(),
Context::STRING_FUNCTION_INDEX,
v0,
&miss);
ASSERT(object != holder);
CheckPrototypes(JSObject::cast(object->GetPrototype()), v0, holder,
a1, a3, t0, name, &miss);
ASSERT(!object.is_identical_to(holder));
CheckPrototypes(Handle<JSObject>(JSObject::cast(object->GetPrototype())),
v0, holder, a1, a3, t0, name, &miss);
Register receiver = v0;
Register index = t1;
......@@ -2172,7 +1845,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
__ LoadRoot(index, Heap::kUndefinedValueRootIndex);
}
StringCharAtGenerator char_at_generator(receiver,
StringCharAtGenerator generator(receiver,
index,
scratch1,
scratch2,
......@@ -2181,12 +1854,12 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
&miss, // When not a number.
index_out_of_range_label,
STRING_INDEX_IS_NUMBER);
char_at_generator.GenerateFast(masm());
generator.GenerateFast(masm());
__ Drop(argc + 1);
__ Ret();
StubRuntimeCallHelper call_helper;
char_at_generator.GenerateSlow(masm(), call_helper);
generator.GenerateSlow(masm(), call_helper);
if (index_out_of_range.is_linked()) {
__ bind(&index_out_of_range);
......@@ -2197,22 +1870,21 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
__ bind(&miss);
// Restore function name in a2.
__ li(a2, Handle<String>(name));
__ li(a2, name);
__ bind(&name_miss);
MaybeObject* maybe_result = TryGenerateMissBranch();
if (maybe_result->IsFailure()) return maybe_result;
GenerateMissBranch();
// Return the generated code.
return TryGetCode(function);
return GetCode(function);
}
MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<JSFunction> function,
Handle<String> name) {
// ----------- S t a t e -------------
// -- a2 : function name
// -- ra : return address
......@@ -2225,22 +1897,23 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
Label miss;
GenerateNameCheck(Handle<String>(name), &miss);
GenerateNameCheck(name, &miss);
if (cell == NULL) {
if (cell.is_null()) {
__ lw(a1, MemOperand(sp, 1 * kPointerSize));
STATIC_ASSERT(kSmiTag == 0);
__ JumpIfSmi(a1, &miss);
CheckPrototypes(JSObject::cast(object), a1, holder, v0, a3, t0, name,
&miss);
CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
name, &miss);
} else {
ASSERT(cell->value() == function);
GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
ASSERT(cell->value() == *function);
GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
&miss);
GenerateLoadFunctionFromCell(cell, function, &miss);
}
......@@ -2256,13 +1929,13 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
// Convert the smi code to uint16.
__ And(code, code, Operand(Smi::FromInt(0xffff)));
StringCharFromCodeGenerator char_from_code_generator(code, v0);
char_from_code_generator.GenerateFast(masm());
StringCharFromCodeGenerator generator(code, v0);
generator.GenerateFast(masm());
__ Drop(argc + 1);
__ Ret();
StubRuntimeCallHelper call_helper;
char_from_code_generator.GenerateSlow(masm(), call_helper);
generator.GenerateSlow(masm(), call_helper);
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
......@@ -2271,19 +1944,19 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
__ bind(&miss);
// a2: function name.
MaybeObject* maybe_result = TryGenerateMissBranch();
if (maybe_result->IsFailure()) return maybe_result;
GenerateMissBranch();
// Return the generated code.
return (cell == NULL) ? TryGetCode(function) : TryGetCode(NORMAL, name);
return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
}
MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
Handle<Code> CallStubCompiler::CompileMathFloorCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<JSFunction> function,
Handle<String> name) {
// ----------- S t a t e -------------
// -- a2 : function name
// -- ra : return address
......@@ -2292,30 +1965,29 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
// -- sp[argc * 4] : receiver
// -----------------------------------
if (!CpuFeatures::IsSupported(FPU))
return heap()->undefined_value();
CpuFeatures::Scope scope_fpu(FPU);
if (!CpuFeatures::IsSupported(FPU)) {
return Handle<Code>::null();
}
CpuFeatures::Scope scope_fpu(FPU);
const int argc = arguments().immediate();
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
Label miss, slow;
GenerateNameCheck(Handle<String>(name), &miss);
GenerateNameCheck(name, &miss);
if (cell == NULL) {
if (cell.is_null()) {
__ lw(a1, MemOperand(sp, 1 * kPointerSize));
STATIC_ASSERT(kSmiTag == 0);
__ JumpIfSmi(a1, &miss);
CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
&miss);
CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
name, &miss);
} else {
ASSERT(cell->value() == function);
GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
ASSERT(cell->value() == *function);
GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
&miss);
GenerateLoadFunctionFromCell(cell, function, &miss);
}
......@@ -2405,19 +2077,19 @@ MaybeObject* CallStubCompiler::CompileMathFloorCall(Object* object,
__ bind(&miss);
// a2: function name.
MaybeObject* obj = TryGenerateMissBranch();
if (obj->IsFailure()) return obj;
GenerateMissBranch();
// Return the generated code.
return (cell == NULL) ? TryGetCode(function) : TryGetCode(NORMAL, name);
return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
}
MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
Handle<Code> CallStubCompiler::CompileMathAbsCall(
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<JSFunction> function,
Handle<String> name) {
// ----------- S t a t e -------------
// -- a2 : function name
// -- ra : return address
......@@ -2427,25 +2099,23 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
// -----------------------------------
const int argc = arguments().immediate();
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
if (!object->IsJSObject() || argc != 1) return heap()->undefined_value();
if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
Label miss;
GenerateNameCheck(Handle<String>(name), &miss);
if (cell == NULL) {
GenerateNameCheck(name, &miss);
if (cell.is_null()) {
__ lw(a1, MemOperand(sp, 1 * kPointerSize));
STATIC_ASSERT(kSmiTag == 0);
__ JumpIfSmi(a1, &miss);
CheckPrototypes(JSObject::cast(object), a1, holder, v0, a3, t0, name,
&miss);
CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, v0, a3, t0,
name, &miss);
} else {
ASSERT(cell->value() == function);
GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss);
ASSERT(cell->value() == *function);
GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
&miss);
GenerateLoadFunctionFromCell(cell, function, &miss);
}
......@@ -2507,37 +2177,36 @@ MaybeObject* CallStubCompiler::CompileMathAbsCall(Object* object,
__ bind(&miss);
// a2: function name.
MaybeObject* maybe_result = TryGenerateMissBranch();
if (maybe_result->IsFailure()) return maybe_result;
GenerateMissBranch();
// Return the generated code.
return (cell == NULL) ? TryGetCode(function) : TryGetCode(NORMAL, name);
return cell.is_null() ? GetCode(function) : GetCode(NORMAL, name);
}
MaybeObject* CallStubCompiler::CompileFastApiCall(
Handle<Code> CallStubCompiler::CompileFastApiCall(
const CallOptimization& optimization,
Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
Handle<Object> object,
Handle<JSObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<JSFunction> function,
Handle<String> name) {
Counters* counters = isolate()->counters();
ASSERT(optimization.is_simple_api_call());
// Bail out if object is a global object as we don't want to
// repatch it to global receiver.
if (object->IsGlobalObject()) return heap()->undefined_value();
if (cell != NULL) return heap()->undefined_value();
if (!object->IsJSObject()) return heap()->undefined_value();
if (object->IsGlobalObject()) return Handle<Code>::null();
if (!cell.is_null()) return Handle<Code>::null();
if (!object->IsJSObject()) return Handle<Code>::null();
int depth = optimization.GetPrototypeDepthOfExpectedType(
JSObject::cast(object), holder);
if (depth == kInvalidProtoDepth) return heap()->undefined_value();
Handle<JSObject>::cast(object), holder);
if (depth == kInvalidProtoDepth) return Handle<Code>::null();
Label miss, miss_before_stack_reserved;
GenerateNameCheck(Handle<String>(name), &miss_before_stack_reserved);
GenerateNameCheck(name, &miss_before_stack_reserved);
// Get the receiver from the stack.
const int argc = arguments().immediate();
......@@ -2552,45 +2221,42 @@ MaybeObject* CallStubCompiler::CompileFastApiCall(
ReserveSpaceForFastApiCall(masm(), a0);
// Check that the maps haven't changed and find a Holder as a side effect.
CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0, name,
depth, &miss);
MaybeObject* result = GenerateFastApiDirectCall(masm(), optimization, argc);
if (result->IsFailure()) return result;
GenerateFastApiDirectCall(masm(), optimization, argc);
__ bind(&miss);
FreeSpaceForFastApiCall(masm());
__ bind(&miss_before_stack_reserved);
MaybeObject* maybe_result = TryGenerateMissBranch();
if (maybe_result->IsFailure()) return maybe_result;
GenerateMissBranch();
// Return the generated code.
return TryGetCode(function);
return GetCode(function);
}
MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
JSObject* holder,
JSFunction* function,
String* name,
Handle<Code> CallStubCompiler::CompileCallConstant(Handle<Object> object,
Handle<JSObject> holder,
Handle<JSFunction> function,
Handle<String> name,
CheckType check) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
// -----------------------------------
if (HasCustomCallGenerator(function)) {
MaybeObject* maybe_result = CompileCustomCall(
object, holder, NULL, function, name);
Object* result;
if (!maybe_result->ToObject(&result)) return maybe_result;
// Undefined means bail out to regular compiler.
if (!result->IsUndefined()) return result;
Handle<Code> code = CompileCustomCall(object, holder,
Handle<JSGlobalPropertyCell>::null(),
function, name);
// A null handle means bail out to the regular compiler code below.
if (!code.is_null()) return code;
}
Label miss;
GenerateNameCheck(Handle<String>(name), &miss);
GenerateNameCheck(name, &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
......@@ -2605,16 +2271,14 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// Make sure that it's okay not to patch the on stack receiver
// unless we're doing a receiver map check.
ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
SharedFunctionInfo* function_info = function->shared();
switch (check) {
case RECEIVER_MAP_CHECK:
__ IncrementCounter(masm()->isolate()->counters()->call_const(),
1, a0, a3);
// Check that the maps haven't changed.
CheckPrototypes(JSObject::cast(object), a1, holder, a0, a3, t0, name,
&miss);
CheckPrototypes(Handle<JSObject>::cast(object), a1, holder, a0, a3, t0,
name, &miss);
// Patch the receiver on the stack with the global proxy if
// necessary.
......@@ -2625,28 +2289,25 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
break;
case STRING_CHECK:
if (!function->IsBuiltin() && !function_info->strict_mode()) {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
} else {
if (function->IsBuiltin() || function->shared()->strict_mode()) {
// Check that the object is a two-byte string or a symbol.
__ GetObjectType(a1, a3, a3);
__ Branch(&miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::STRING_FUNCTION_INDEX, a0, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
a1, t0, name, &miss);
}
break;
case NUMBER_CHECK: {
if (!function->IsBuiltin() && !function_info->strict_mode()) {
CheckPrototypes(
Handle<JSObject>(JSObject::cast(object->GetPrototype())),
a0, holder, a3, a1, t0, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
} else {
}
break;
case NUMBER_CHECK:
if (function->IsBuiltin() || function->shared()->strict_mode()) {
Label fast;
// Check that the object is a smi or a heap number.
__ And(t1, a1, Operand(kSmiTagMask));
......@@ -2657,18 +2318,18 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::NUMBER_FUNCTION_INDEX, a0, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
a1, t0, name, &miss);
}
break;
}
case BOOLEAN_CHECK: {
if (!function->IsBuiltin() && !function_info->strict_mode()) {
CheckPrototypes(
Handle<JSObject>(JSObject::cast(object->GetPrototype())),
a0, holder, a3, a1, t0, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
} else {
}
break;
case BOOLEAN_CHECK:
if (function->IsBuiltin() || function->shared()->strict_mode()) {
Label fast;
// Check that the object is a boolean.
__ LoadRoot(t0, Heap::kTrueValueRootIndex);
......@@ -2679,16 +2340,17 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::BOOLEAN_FUNCTION_INDEX, a0, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), a0, holder, a3,
a1, t0, name, &miss);
CheckPrototypes(
Handle<JSObject>(JSObject::cast(object->GetPrototype())),
a0, holder, a3, a1, t0, name, &miss);
} else {
// Calling non-strict non-builtins with a value as the receiver
// requires boxing.
__ jmp(&miss);
}
break;
}
default:
UNREACHABLE();
}
CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
......@@ -2697,17 +2359,16 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// Handle call cache miss.
__ bind(&miss);
MaybeObject* maybe_result = TryGenerateMissBranch();
if (maybe_result->IsFailure()) return maybe_result;
GenerateMissBranch();
// Return the generated code.
return TryGetCode(function);
return GetCode(function);
}
MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
JSObject* holder,
String* name) {
Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
Handle<JSObject> holder,
Handle<String> name) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
......@@ -2715,11 +2376,10 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
Label miss;
GenerateNameCheck(Handle<String>(name), &miss);
GenerateNameCheck(name, &miss);
// Get the number of arguments.
const int argc = arguments().immediate();
LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
......@@ -2727,64 +2387,47 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
__ lw(a1, MemOperand(sp, argc * kPointerSize));
CallInterceptorCompiler compiler(this, arguments(), a2, extra_state_);
MaybeObject* result = compiler.Compile(masm(),
object,
holder,
name,
&lookup,
a1,
a3,
t0,
a0,
compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
&miss);
if (result->IsFailure()) {
return result;
}
// Move returned value, the function to call, to a1.
__ mov(a1, v0);
// Restore receiver.
__ lw(a0, MemOperand(sp, argc * kPointerSize));
GenerateCallFunction(masm(), Handle<Object>(object), arguments(), &miss,
extra_state_);
GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
// Handle call cache miss.
__ bind(&miss);
MaybeObject* maybe_result = TryGenerateMissBranch();
if (maybe_result->IsFailure()) return maybe_result;
GenerateMissBranch();
// Return the generated code.
return TryGetCode(INTERCEPTOR, name);
return GetCode(INTERCEPTOR, name);
}
MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
GlobalObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
Handle<Code> CallStubCompiler::CompileCallGlobal(
Handle<JSObject> object,
Handle<GlobalObject> holder,
Handle<JSGlobalPropertyCell> cell,
Handle<JSFunction> function,
Handle<String> name) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
// -----------------------------------
if (HasCustomCallGenerator(function)) {
MaybeObject* maybe_result = CompileCustomCall(
object, holder, cell, function, name);
Object* result;
if (!maybe_result->ToObject(&result)) return maybe_result;
// Undefined means bail out to regular compiler.
if (!result->IsUndefined()) return result;
Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
// A null handle means bail out to the regular compiler code below.
if (!code.is_null()) return code;
}
Label miss;
GenerateNameCheck(Handle<String>(name), &miss);
GenerateNameCheck(name, &miss);
// Get the number of arguments.
const int argc = arguments().immediate();
GenerateGlobalReceiverCheck(object, holder, name, &miss);
GenerateLoadFunctionFromCell(cell, function, &miss);
......@@ -2801,7 +2444,6 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
// Jump to the cached code (tail call).
Counters* counters = masm()->isolate()->counters();
__ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
Handle<Code> code(function->code());
ParameterCount expected(function->shared()->formal_parameter_count());
CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION
......@@ -2816,11 +2458,10 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
// Handle call cache miss.
__ bind(&miss);
__ IncrementCounter(counters->call_global_inline_miss(), 1, a1, a3);
MaybeObject* maybe_result = TryGenerateMissBranch();
if (maybe_result->IsFailure()) return maybe_result;
GenerateMissBranch();
// Return the generated code.
return TryGetCode(NORMAL, name);
return GetCode(NORMAL, name);
}
......@@ -3053,29 +2694,24 @@ Handle<Code> LoadStubCompiler::CompileLoadField(Handle<JSObject> object,
}
MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name,
JSObject* object,
JSObject* holder,
AccessorInfo* callback) {
Handle<Code> LoadStubCompiler::CompileLoadCallback(
Handle<String> name,
Handle<JSObject> object,
Handle<JSObject> holder,
Handle<AccessorInfo> callback) {
// ----------- S t a t e -------------
// -- a0 : receiver
// -- a2 : name
// -- ra : return address
// -----------------------------------
Label miss;
MaybeObject* result = GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0,
callback, name, &miss);
if (result->IsFailure()) {
miss.Unuse();
return result;
}
GenerateLoadCallback(object, holder, a0, a2, a3, a1, t0, callback, name,
&miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
return TryGetCode(CALLBACKS, name);
return GetCode(CALLBACKS, name);
}
......@@ -3099,9 +2735,9 @@ Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
}
MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
JSObject* holder,
String* name) {
Handle<Code> LoadStubCompiler::CompileLoadInterceptor(Handle<JSObject> object,
Handle<JSObject> holder,
Handle<String> name) {
// ----------- S t a t e -------------
// -- a0 : receiver
// -- a2 : name
......@@ -3112,21 +2748,13 @@ MaybeObject* LoadStubCompiler::CompileLoadInterceptor(JSObject* object,
LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
GenerateLoadInterceptor(object,
holder,
&lookup,
a0,
a2,
a3,
a1,
t0,
name,
GenerateLoadInterceptor(object, holder, &lookup, a0, a2, a3, a1, t0, name,
&miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
return TryGetCode(INTERCEPTOR, name);
return GetCode(INTERCEPTOR, name);
}
......@@ -3200,11 +2828,11 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadField(Handle<String> name,
}
MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
String* name,
JSObject* receiver,
JSObject* holder,
AccessorInfo* callback) {
Handle<Code> KeyedLoadStubCompiler::CompileLoadCallback(
Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<AccessorInfo> callback) {
// ----------- S t a t e -------------
// -- ra : return address
// -- a0 : key
......@@ -3213,19 +2841,14 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback(
Label miss;
// Check the key is the cached one.
__ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
MaybeObject* result = GenerateLoadCallback(receiver, holder, a1, a0, a2, a3,
t0, callback, name, &miss);
if (result->IsFailure()) {
miss.Unuse();
return result;
}
__ Branch(&miss, ne, a0, Operand(name));
GenerateLoadCallback(receiver, holder, a1, a0, a2, a3, t0, callback, name,
&miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
return TryGetCode(CALLBACKS, name);
return GetCode(CALLBACKS, name);
}
......@@ -3253,9 +2876,10 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadConstant(
}
MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
JSObject* holder,
String* name) {
Handle<Code> KeyedLoadStubCompiler::CompileLoadInterceptor(
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<String> name) {
// ----------- S t a t e -------------
// -- ra : return address
// -- a0 : key
......@@ -3264,24 +2888,16 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
Label miss;
// Check the key is the cached one.
__ Branch(&miss, ne, a0, Operand(Handle<String>(name)));
__ Branch(&miss, ne, a0, Operand(name));
LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
GenerateLoadInterceptor(receiver,
holder,
&lookup,
a1,
a0,
a2,
a3,
t0,
name,
GenerateLoadInterceptor(receiver, holder, &lookup, a1, a0, a2, a3, t0, name,
&miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
return TryGetCode(INTERCEPTOR, name);
return GetCode(INTERCEPTOR, name);
}
......@@ -3496,7 +3112,8 @@ Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
}
MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
Handle<Code> ConstructStubCompiler::CompileConstructStub(
Handle<JSFunction> function) {
// a0 : argc
// a1 : constructor
// ra : return address
......@@ -3541,12 +3158,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
// a2: initial map
// t7: undefined
__ lbu(a3, FieldMemOperand(a2, Map::kInstanceSizeOffset));
__ AllocateInNewSpace(a3,
t4,
t5,
t6,
&generic_stub_call,
SIZE_IN_WORDS);
__ AllocateInNewSpace(a3, t4, t5, t6, &generic_stub_call, SIZE_IN_WORDS);
// Allocated the JSObject, now initialize the fields. Map is set to initial
// map and properties and elements are set to empty fixed array.
......@@ -3581,7 +3193,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
// t7: undefined
// Fill the initialized properties with a constant value or a passed argument
// depending on the this.x = ...; assignment in the function.
SharedFunctionInfo* shared = function->shared();
Handle<SharedFunctionInfo> shared(function->shared());
for (int i = 0; i < shared->this_property_assignments_count(); i++) {
if (shared->IsThisPropertyAssignmentArgument(i)) {
Label not_passed, next;
......@@ -4053,9 +3665,9 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
__ bind(&miss_force_generic);
Code* stub = masm->isolate()->builtins()->builtin(
Builtins::kKeyedLoadIC_MissForceGeneric);
__ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
Handle<Code> stub =
masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
__ Jump(stub, RelocInfo::CODE_TARGET);
}
......@@ -4483,9 +4095,9 @@ void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) {
__ Ret();
__ bind(&miss_force_generic);
Code* stub = masm->isolate()->builtins()->builtin(
Builtins::kKeyedLoadIC_MissForceGeneric);
__ Jump(Handle<Code>(stub), RelocInfo::CODE_TARGET);
Handle<Code> stub =
masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
__ Jump(stub, RelocInfo::CODE_TARGET);
}
......
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