Handlify CallStubCompiler::CompileCallField.

This function relies on a number of helpers for checking prototypes and
probing dictionaries.  It is not possible to wrap these helpers to retry
after allocation failure in a safe way---the assembler has no way to undo
what it has already assembled.

These functions have all been duplicated with handle and raw versions.  The
raw versions will eventually be removed completely.

R=ulan@chromium.org,vegorov@chromium.org
BUG=
TEST=

Review URL: http://codereview.chromium.org/8332003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9769 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent a8a242ad
......@@ -6677,7 +6677,82 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
}
MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register receiver,
Register properties,
Handle<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.
__ ldr(index, FieldMemOperand(properties, kCapacityOffset));
__ sub(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);
__ add(index, index, Operand(index, LSL, 1)); // index *= 3.
Register entity_name = scratch0;
// Having undefined at this place means the name is not contained.
ASSERT_EQ(kSmiTagSize, 1);
Register tmp = properties;
__ add(tmp, properties, Operand(index, LSL, 1));
__ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
ASSERT(!tmp.is(entity_name));
__ LoadRoot(tmp, Heap::kUndefinedValueRootIndex);
__ cmp(entity_name, tmp);
__ b(eq, done);
if (i != kInlinedProbes - 1) {
// Stop if found the property.
__ cmp(entity_name, Operand(Handle<String>(name)));
__ b(eq, miss);
// Check if the entry name is not a symbol.
__ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
__ ldrb(entity_name,
FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
__ tst(entity_name, Operand(kIsSymbolMask));
__ b(eq, miss);
// Restore the properties.
__ ldr(properties,
FieldMemOperand(receiver, JSObject::kPropertiesOffset));
}
}
const int spill_mask =
(lr.bit() | r6.bit() | r5.bit() | r4.bit() | r3.bit() |
r2.bit() | r1.bit() | r0.bit());
__ stm(db_w, sp, spill_mask);
__ ldr(r0, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
__ mov(r1, Operand(Handle<String>(name)));
StringDictionaryLookupStub stub(NEGATIVE_LOOKUP);
__ CallStub(&stub);
__ tst(r0, Operand(r0));
__ ldm(ia_w, sp, spill_mask);
__ b(eq, done);
__ b(ne, miss);
}
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MaybeObject* StringDictionaryLookupStub::TryGenerateNegativeLookup(
MacroAssembler* masm,
Label* miss,
Label* done,
......
......@@ -799,7 +799,17 @@ class StringDictionaryLookupStub: public CodeStub {
void Generate(MacroAssembler* masm);
MUST_USE_RESULT static MaybeObject* GenerateNegativeLookup(
static void GenerateNegativeLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register receiver,
Register properties,
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,
......
This diff is collapsed.
......@@ -6541,7 +6541,67 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
// must always call a backup property check that is complete.
// This function is safe to call if the receiver has fast properties.
// Name must be a symbol and receiver must be a heap object.
MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register properties,
Handle<String> name,
Register r0) {
ASSERT(name->IsSymbol());
// 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++) {
// Compute the masked index: (hash + i + i * i) & mask.
Register index = r0;
// Capacity is smi 2^n.
__ mov(index, FieldOperand(properties, kCapacityOffset));
__ dec(index);
__ and_(index,
Immediate(Smi::FromInt(name->Hash() +
StringDictionary::GetProbeOffset(i))));
// Scale the index by multiplying by the entry size.
ASSERT(StringDictionary::kEntrySize == 3);
__ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
Register entity_name = r0;
// Having undefined at this place means the name is not contained.
ASSERT_EQ(kSmiTagSize, 1);
__ mov(entity_name, Operand(properties, index, times_half_pointer_size,
kElementsStartOffset - kHeapObjectTag));
__ cmp(entity_name, masm->isolate()->factory()->undefined_value());
__ j(equal, done);
// Stop if found the property.
__ cmp(entity_name, Handle<String>(name));
__ j(equal, miss);
// Check if the entry name is not a symbol.
__ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
__ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
kIsSymbolMask);
__ j(zero, miss);
}
StringDictionaryLookupStub stub(properties,
r0,
r0,
StringDictionaryLookupStub::NEGATIVE_LOOKUP);
__ push(Immediate(Handle<Object>(name)));
__ push(Immediate(name->Hash()));
__ CallStub(&stub);
__ test(r0, r0);
__ j(not_zero, miss);
__ jmp(done);
}
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MaybeObject* StringDictionaryLookupStub::TryGenerateNegativeLookup(
MacroAssembler* masm,
Label* miss,
Label* done,
......
......@@ -421,7 +421,16 @@ class StringDictionaryLookupStub: public CodeStub {
void Generate(MacroAssembler* masm);
MUST_USE_RESULT static MaybeObject* GenerateNegativeLookup(
static void GenerateNegativeLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register properties,
Handle<String> name,
Register r0);
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MUST_USE_RESULT static MaybeObject* TryGenerateNegativeLookup(
MacroAssembler* masm,
Label* miss,
Label* done,
......
This diff is collapsed.
......@@ -11472,6 +11472,16 @@ JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
}
Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
Handle<GlobalObject> global,
Handle<String> name) {
Isolate* isolate = global->GetIsolate();
CALL_HEAP_FUNCTION(isolate,
global->EnsurePropertyCell(*name),
JSGlobalPropertyCell);
}
MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
ASSERT(!HasFastProperties());
int entry = property_dictionary()->FindEntry(name);
......
......@@ -5395,6 +5395,11 @@ class GlobalObject: public JSObject {
}
// Ensure that the global object has a cell for the given property name.
static Handle<JSGlobalPropertyCell> EnsurePropertyCell(
Handle<GlobalObject> global,
Handle<String> name);
// TODO(kmillikin): This function can be eliminated once the stub cache is
// full handlified (and the static helper can be written directly).
MUST_USE_RESULT MaybeObject* EnsurePropertyCell(String* name);
// Casting.
......
......@@ -835,17 +835,6 @@ Handle<Code> StubCache::ComputeCallConstant(int argc,
}
Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
Handle<JSObject> holder,
int index,
Handle<String> name) {
CALL_HEAP_FUNCTION(
isolate(),
(set_failure(NULL), CompileCallField(*object, *holder, index, *name)),
Code);
}
Handle<Code> StubCache::ComputeCallField(int argc,
Code::Kind kind,
Code::ExtraICState extra_state,
......@@ -1634,6 +1623,14 @@ Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
}
Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
Handle<String> name) {
return (FLAG_print_code_stubs && !name.is_null())
? GetCodeWithFlags(flags, *name->ToCString())
: GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
}
MaybeObject* StubCompiler::TryGetCodeWithFlags(Code::Flags flags,
const char* name) {
// Check for allocation failures during stub compilation.
......@@ -1654,7 +1651,7 @@ MaybeObject* StubCompiler::TryGetCodeWithFlags(Code::Flags flags,
MaybeObject* StubCompiler::TryGetCodeWithFlags(Code::Flags flags,
String* name) {
if (FLAG_print_code_stubs && (name != NULL)) {
if (FLAG_print_code_stubs && name != NULL) {
return TryGetCodeWithFlags(flags, *name->ToCString());
}
return TryGetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
......@@ -1814,7 +1811,29 @@ MaybeObject* CallStubCompiler::CompileCustomCall(Object* object,
}
MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
Handle<Code> CallStubCompiler::GetCode(PropertyType type, Handle<String> name) {
int argc = arguments_.immediate();
Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
type,
extra_state_,
cache_holder_,
argc);
return GetCodeWithFlags(flags, name);
}
Handle<Code> CallStubCompiler::GetCode(Handle<JSFunction> function) {
Handle<String> function_name;
if (function->shared()->name()->IsString()) {
function_name = Handle<String>(String::cast(function->shared()->name()));
}
return GetCode(CONSTANT_FUNCTION, function_name);
}
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MaybeObject* CallStubCompiler::TryGetCode(PropertyType type, String* name) {
int argc = arguments_.immediate();
Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
type,
......@@ -1825,12 +1844,14 @@ MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
}
MaybeObject* CallStubCompiler::GetCode(JSFunction* function) {
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MaybeObject* CallStubCompiler::TryGetCode(JSFunction* function) {
String* function_name = NULL;
if (function->shared()->name()->IsString()) {
function_name = String::cast(function->shared()->name());
}
return GetCode(CONSTANT_FUNCTION, function_name);
return TryGetCode(CONSTANT_FUNCTION, function_name);
}
......
......@@ -416,8 +416,10 @@ class StubCompiler BASE_EMBEDDED {
Label* miss);
static void GenerateFastPropertyLoad(MacroAssembler* masm,
Register dst, Register src,
JSObject* holder, int index);
Register dst,
Register src,
Handle<JSObject> holder,
int index);
static void GenerateLoadArrayLength(MacroAssembler* masm,
Register receiver,
......@@ -466,7 +468,30 @@ class StubCompiler BASE_EMBEDDED {
// The function can optionally (when save_at_depth !=
// kInvalidProtoDepth) save the object at the given depth by moving
// it to [esp + kPointerSize].
Register CheckPrototypes(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
Register holder_reg,
Register scratch1,
Register scratch2,
Handle<String> name,
Label* miss) {
return CheckPrototypes(object, object_reg, holder, holder_reg, scratch1,
scratch2, name, kInvalidProtoDepth, miss);
}
Register CheckPrototypes(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
Register holder_reg,
Register scratch1,
Register scratch2,
Handle<String> name,
int save_at_depth,
Label* miss);
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
Register CheckPrototypes(JSObject* object,
Register object_reg,
JSObject* holder,
......@@ -479,6 +504,8 @@ class StubCompiler BASE_EMBEDDED {
scratch2, name, kInvalidProtoDepth, miss);
}
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
Register CheckPrototypes(JSObject* object,
Register object_reg,
JSObject* holder,
......@@ -491,6 +518,7 @@ class StubCompiler BASE_EMBEDDED {
protected:
Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<String> name);
MUST_USE_RESULT MaybeObject* TryGetCodeWithFlags(Code::Flags flags,
const char* name);
......@@ -826,11 +854,6 @@ class CallStubCompiler: public StubCompiler {
int index,
Handle<String> name);
MUST_USE_RESULT MaybeObject* CompileCallField(JSObject* object,
JSObject* holder,
int index,
String* name);
Handle<Code> CompileCallConstant(Handle<Object> object,
Handle<JSObject> holder,
Handle<JSFunction> function,
......@@ -899,13 +922,15 @@ class CallStubCompiler: public StubCompiler {
const ParameterCount& arguments() { return arguments_; }
MUST_USE_RESULT MaybeObject* GetCode(PropertyType type, String* name);
Handle<Code> GetCode(PropertyType type, Handle<String> name);
Handle<Code> GetCode(Handle<JSFunction> function);
// Convenience function. Calls GetCode above passing
// CONSTANT_FUNCTION type and the name of the given function.
MUST_USE_RESULT MaybeObject* GetCode(JSFunction* function);
// TODO(kmillikin): Eliminate these functions when the stub cache is fully
// handlified.
MUST_USE_RESULT MaybeObject* TryGetCode(PropertyType type, String* name);
MUST_USE_RESULT MaybeObject* TryGetCode(JSFunction* function);
void GenerateNameCheck(String* name, Label* miss);
void GenerateNameCheck(Handle<String> name, Label* miss);
void GenerateGlobalReceiverCheck(JSObject* object,
JSObject* holder,
......@@ -918,9 +943,12 @@ class CallStubCompiler: public StubCompiler {
JSFunction* function,
Label* miss);
// Generates a jump to CallIC miss stub. Returns Failure if the jump cannot
// be generated.
MUST_USE_RESULT MaybeObject* GenerateMissBranch();
// Generates a jump to CallIC miss stub.
void GenerateMissBranch();
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MUST_USE_RESULT MaybeObject* TryGenerateMissBranch();
};
......
......@@ -5461,7 +5461,68 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
}
MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup(
void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register properties,
Handle<String> name,
Register r0) {
// 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++) {
// r0 points to properties hash.
// Compute the masked index: (hash + i + i * i) & mask.
Register index = r0;
// Capacity is smi 2^n.
__ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset));
__ decl(index);
__ and_(index,
Immediate(name->Hash() + StringDictionary::GetProbeOffset(i)));
// Scale the index by multiplying by the entry size.
ASSERT(StringDictionary::kEntrySize == 3);
__ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
Register entity_name = r0;
// Having undefined at this place means the name is not contained.
ASSERT_EQ(kSmiTagSize, 1);
__ movq(entity_name, Operand(properties,
index,
times_pointer_size,
kElementsStartOffset - kHeapObjectTag));
__ Cmp(entity_name, masm->isolate()->factory()->undefined_value());
__ j(equal, done);
// Stop if found the property.
__ Cmp(entity_name, Handle<String>(name));
__ j(equal, miss);
// Check if the entry name is not a symbol.
__ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
__ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
Immediate(kIsSymbolMask));
__ j(zero, miss);
}
StringDictionaryLookupStub stub(properties,
r0,
r0,
StringDictionaryLookupStub::NEGATIVE_LOOKUP);
__ Push(Handle<Object>(name));
__ push(Immediate(name->Hash()));
__ CallStub(&stub);
__ testq(r0, r0);
__ j(not_zero, miss);
__ jmp(done);
}
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MaybeObject* StringDictionaryLookupStub::TryGenerateNegativeLookup(
MacroAssembler* masm,
Label* miss,
Label* done,
......
......@@ -423,7 +423,16 @@ class StringDictionaryLookupStub: public CodeStub {
void Generate(MacroAssembler* masm);
MUST_USE_RESULT static MaybeObject* GenerateNegativeLookup(
static void GenerateNegativeLookup(MacroAssembler* masm,
Label* miss,
Label* done,
Register properties,
Handle<String> name,
Register r0);
// TODO(kmillikin): Eliminate this function when the stub cache is fully
// handlified.
MUST_USE_RESULT static MaybeObject* TryGenerateNegativeLookup(
MacroAssembler* masm,
Label* miss,
Label* done,
......
This diff is collapsed.
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