ES6 symbols: Allow symbols as property names
Since symbols and strings share a common representation, most of this change is about consistently replacing 'String' with 'Name' in all places where property names are expected. In particular, no new logic at all is necessary for maps, property dictionaries, or transitions. :) The only places where an actual case distinction is needed have to do with generated type checks, and with conversions of names to strings (especially in logger and profiler). Left in some TODOs wrt to the API: interceptors and native getters don't accept symbols as property names yet, because that would require extending the external v8.h. (Baseline CL: https://codereview.chromium.org/12296026/) R=verwaest@chromium.org,mstarzinger@chromium.org BUG=v8:2158 Review URL: https://codereview.chromium.org/12330012 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13811 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
74a25d8e17
commit
5c93b18eb2
@ -7425,13 +7425,14 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register receiver,
|
||||
Register properties,
|
||||
Handle<String> name,
|
||||
Register scratch0) {
|
||||
void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register receiver,
|
||||
Register properties,
|
||||
Handle<Name> name,
|
||||
Register scratch0) {
|
||||
ASSERT(name->IsUniqueName());
|
||||
// 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
|
||||
@ -7445,10 +7446,10 @@ void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
__ ldr(index, FieldMemOperand(properties, kCapacityOffset));
|
||||
__ sub(index, index, Operand(1));
|
||||
__ and_(index, index, Operand(
|
||||
Smi::FromInt(name->Hash() + StringDictionary::GetProbeOffset(i))));
|
||||
Smi::FromInt(name->Hash() + NameDictionary::GetProbeOffset(i))));
|
||||
|
||||
// Scale the index by multiplying by the entry size.
|
||||
ASSERT(StringDictionary::kEntrySize == 3);
|
||||
ASSERT(NameDictionary::kEntrySize == 3);
|
||||
__ add(index, index, Operand(index, LSL, 1)); // index *= 3.
|
||||
|
||||
Register entity_name = scratch0;
|
||||
@ -7468,21 +7469,23 @@ void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
__ LoadRoot(tmp, Heap::kTheHoleValueRootIndex);
|
||||
|
||||
// Stop if found the property.
|
||||
__ cmp(entity_name, Operand(Handle<String>(name)));
|
||||
__ cmp(entity_name, Operand(Handle<Name>(name)));
|
||||
__ b(eq, miss);
|
||||
|
||||
Label the_hole;
|
||||
Label good;
|
||||
__ cmp(entity_name, tmp);
|
||||
__ b(eq, &the_hole);
|
||||
__ b(eq, &good);
|
||||
|
||||
// Check if the entry name is not an internalized string.
|
||||
// Check if the entry name is not a unique name.
|
||||
__ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
|
||||
__ ldrb(entity_name,
|
||||
FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
|
||||
__ tst(entity_name, Operand(kIsInternalizedMask));
|
||||
__ b(eq, miss);
|
||||
__ b(ne, &good);
|
||||
__ cmp(entity_name, Operand(SYMBOL_TYPE));
|
||||
__ b(ne, miss);
|
||||
|
||||
__ bind(&the_hole);
|
||||
__ bind(&good);
|
||||
|
||||
// Restore the properties.
|
||||
__ ldr(properties,
|
||||
@ -7496,8 +7499,8 @@ void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
|
||||
__ stm(db_w, sp, spill_mask);
|
||||
__ ldr(r0, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
|
||||
__ mov(r1, Operand(Handle<String>(name)));
|
||||
StringDictionaryLookupStub stub(NEGATIVE_LOOKUP);
|
||||
__ mov(r1, Operand(Handle<Name>(name)));
|
||||
NameDictionaryLookupStub stub(NEGATIVE_LOOKUP);
|
||||
__ CallStub(&stub);
|
||||
__ cmp(r0, Operand::Zero());
|
||||
__ ldm(ia_w, sp, spill_mask);
|
||||
@ -7507,23 +7510,23 @@ void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Probe the string dictionary in the |elements| register. Jump to the
|
||||
// Probe the name 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.
|
||||
// If lookup was successful |scratch2| will be equal to elements + 4 * index.
|
||||
void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register elements,
|
||||
Register name,
|
||||
Register scratch1,
|
||||
Register scratch2) {
|
||||
void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register elements,
|
||||
Register name,
|
||||
Register scratch1,
|
||||
Register scratch2) {
|
||||
ASSERT(!elements.is(scratch1));
|
||||
ASSERT(!elements.is(scratch2));
|
||||
ASSERT(!name.is(scratch1));
|
||||
ASSERT(!name.is(scratch2));
|
||||
|
||||
__ AssertString(name);
|
||||
__ AssertName(name);
|
||||
|
||||
// Compute the capacity mask.
|
||||
__ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
|
||||
@ -7535,20 +7538,20 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
// cover ~93% of loads from dictionaries.
|
||||
for (int i = 0; i < kInlinedProbes; i++) {
|
||||
// Compute the masked index: (hash + i + i * i) & mask.
|
||||
__ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
|
||||
__ ldr(scratch2, FieldMemOperand(name, Name::kHashFieldOffset));
|
||||
if (i > 0) {
|
||||
// Add the probe offset (i + i * i) left shifted to avoid right shifting
|
||||
// the hash in a separate instruction. The value hash + i + i * i is right
|
||||
// shifted in the following and instruction.
|
||||
ASSERT(StringDictionary::GetProbeOffset(i) <
|
||||
1 << (32 - String::kHashFieldOffset));
|
||||
ASSERT(NameDictionary::GetProbeOffset(i) <
|
||||
1 << (32 - Name::kHashFieldOffset));
|
||||
__ add(scratch2, scratch2, Operand(
|
||||
StringDictionary::GetProbeOffset(i) << String::kHashShift));
|
||||
NameDictionary::GetProbeOffset(i) << Name::kHashShift));
|
||||
}
|
||||
__ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift));
|
||||
__ and_(scratch2, scratch1, Operand(scratch2, LSR, Name::kHashShift));
|
||||
|
||||
// Scale the index by multiplying by the element size.
|
||||
ASSERT(StringDictionary::kEntrySize == 3);
|
||||
ASSERT(NameDictionary::kEntrySize == 3);
|
||||
// scratch2 = scratch2 * 3.
|
||||
__ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
|
||||
|
||||
@ -7573,7 +7576,7 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
__ Move(r0, elements);
|
||||
__ Move(r1, name);
|
||||
}
|
||||
StringDictionaryLookupStub stub(POSITIVE_LOOKUP);
|
||||
NameDictionaryLookupStub stub(POSITIVE_LOOKUP);
|
||||
__ CallStub(&stub);
|
||||
__ cmp(r0, Operand::Zero());
|
||||
__ mov(scratch2, Operand(r2));
|
||||
@ -7584,15 +7587,15 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
// This stub overrides SometimesSetsUpAFrame() to return false. That means
|
||||
// we cannot call anything that could cause a GC from this stub.
|
||||
// Registers:
|
||||
// result: StringDictionary to probe
|
||||
// result: NameDictionary to probe
|
||||
// r1: key
|
||||
// : StringDictionary to probe.
|
||||
// index_: will hold an index of entry if lookup is successful.
|
||||
// might alias with result_.
|
||||
// dictionary: NameDictionary to probe.
|
||||
// index: will hold an index of entry if lookup is successful.
|
||||
// might alias with result_.
|
||||
// Returns:
|
||||
// result_ is zero if lookup failed, non zero otherwise.
|
||||
|
||||
@ -7611,7 +7614,7 @@ void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
__ mov(mask, Operand(mask, ASR, kSmiTagSize));
|
||||
__ sub(mask, mask, Operand(1));
|
||||
|
||||
__ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
|
||||
__ ldr(hash, FieldMemOperand(key, Name::kHashFieldOffset));
|
||||
|
||||
__ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
|
||||
|
||||
@ -7622,17 +7625,17 @@ void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
// Add the probe offset (i + i * i) left shifted to avoid right shifting
|
||||
// the hash in a separate instruction. The value hash + i + i * i is right
|
||||
// shifted in the following and instruction.
|
||||
ASSERT(StringDictionary::GetProbeOffset(i) <
|
||||
1 << (32 - String::kHashFieldOffset));
|
||||
ASSERT(NameDictionary::GetProbeOffset(i) <
|
||||
1 << (32 - Name::kHashFieldOffset));
|
||||
__ add(index, hash, Operand(
|
||||
StringDictionary::GetProbeOffset(i) << String::kHashShift));
|
||||
NameDictionary::GetProbeOffset(i) << Name::kHashShift));
|
||||
} else {
|
||||
__ mov(index, Operand(hash));
|
||||
}
|
||||
__ and_(index, mask, Operand(index, LSR, String::kHashShift));
|
||||
__ and_(index, mask, Operand(index, LSR, Name::kHashShift));
|
||||
|
||||
// Scale the index by multiplying by the entry size.
|
||||
ASSERT(StringDictionary::kEntrySize == 3);
|
||||
ASSERT(NameDictionary::kEntrySize == 3);
|
||||
__ add(index, index, Operand(index, LSL, 1)); // index *= 3.
|
||||
|
||||
ASSERT_EQ(kSmiTagSize, 1);
|
||||
@ -7648,12 +7651,16 @@ void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
__ b(eq, &in_dictionary);
|
||||
|
||||
if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
|
||||
// Check if the entry name is not an internalized string.
|
||||
// Check if the entry name is not a unique name.
|
||||
Label cont;
|
||||
__ ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset));
|
||||
__ ldrb(entry_key,
|
||||
FieldMemOperand(entry_key, Map::kInstanceTypeOffset));
|
||||
__ tst(entry_key, Operand(kIsInternalizedMask));
|
||||
__ b(eq, &maybe_in_dictionary);
|
||||
__ b(ne, &cont);
|
||||
__ cmp(entry_key, Operand(SYMBOL_TYPE));
|
||||
__ b(ne, &maybe_in_dictionary);
|
||||
__ bind(&cont);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -745,11 +745,11 @@ class FloatingPointHelper : public AllStatic {
|
||||
};
|
||||
|
||||
|
||||
class StringDictionaryLookupStub: public PlatformCodeStub {
|
||||
class NameDictionaryLookupStub: public PlatformCodeStub {
|
||||
public:
|
||||
enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
|
||||
|
||||
explicit StringDictionaryLookupStub(LookupMode mode) : mode_(mode) { }
|
||||
explicit NameDictionaryLookupStub(LookupMode mode) : mode_(mode) { }
|
||||
|
||||
void Generate(MacroAssembler* masm);
|
||||
|
||||
@ -758,7 +758,7 @@ class StringDictionaryLookupStub: public PlatformCodeStub {
|
||||
Label* done,
|
||||
Register receiver,
|
||||
Register properties,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register scratch0);
|
||||
|
||||
static void GeneratePositiveLookup(MacroAssembler* masm,
|
||||
@ -776,14 +776,14 @@ class StringDictionaryLookupStub: public PlatformCodeStub {
|
||||
static const int kTotalProbes = 20;
|
||||
|
||||
static const int kCapacityOffset =
|
||||
StringDictionary::kHeaderSize +
|
||||
StringDictionary::kCapacityIndex * kPointerSize;
|
||||
NameDictionary::kHeaderSize +
|
||||
NameDictionary::kCapacityIndex * kPointerSize;
|
||||
|
||||
static const int kElementsStartOffset =
|
||||
StringDictionary::kHeaderSize +
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
NameDictionary::kHeaderSize +
|
||||
NameDictionary::kElementsStartIndex * kPointerSize;
|
||||
|
||||
Major MajorKey() { return StringDictionaryLookup; }
|
||||
Major MajorKey() { return NameDictionaryLookup; }
|
||||
|
||||
int MinorKey() {
|
||||
return LookupModeBits::encode(mode_);
|
||||
|
@ -64,12 +64,12 @@ static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
|
||||
|
||||
// Generated code falls through if the receiver is a regular non-global
|
||||
// JS object with slow properties and no interceptors.
|
||||
static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register elements,
|
||||
Register t0,
|
||||
Register t1,
|
||||
Label* miss) {
|
||||
static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register elements,
|
||||
Register t0,
|
||||
Register t1,
|
||||
Label* miss) {
|
||||
// Register usage:
|
||||
// receiver: holds the receiver on entry and is unchanged.
|
||||
// elements: holds the property dictionary on fall through.
|
||||
@ -131,19 +131,19 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
|
||||
Label done;
|
||||
|
||||
// Probe the dictionary.
|
||||
StringDictionaryLookupStub::GeneratePositiveLookup(masm,
|
||||
miss,
|
||||
&done,
|
||||
elements,
|
||||
name,
|
||||
scratch1,
|
||||
scratch2);
|
||||
NameDictionaryLookupStub::GeneratePositiveLookup(masm,
|
||||
miss,
|
||||
&done,
|
||||
elements,
|
||||
name,
|
||||
scratch1,
|
||||
scratch2);
|
||||
|
||||
// If probing finds an entry check that the value is a normal
|
||||
// property.
|
||||
__ bind(&done); // scratch2 == elements + 4 * index
|
||||
const int kElementsStartOffset = StringDictionary::kHeaderSize +
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
const int kElementsStartOffset = NameDictionary::kHeaderSize +
|
||||
NameDictionary::kElementsStartIndex * kPointerSize;
|
||||
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
|
||||
__ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
|
||||
__ tst(scratch1, Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
|
||||
@ -180,19 +180,19 @@ static void GenerateDictionaryStore(MacroAssembler* masm,
|
||||
Label done;
|
||||
|
||||
// Probe the dictionary.
|
||||
StringDictionaryLookupStub::GeneratePositiveLookup(masm,
|
||||
miss,
|
||||
&done,
|
||||
elements,
|
||||
name,
|
||||
scratch1,
|
||||
scratch2);
|
||||
NameDictionaryLookupStub::GeneratePositiveLookup(masm,
|
||||
miss,
|
||||
&done,
|
||||
elements,
|
||||
name,
|
||||
scratch1,
|
||||
scratch2);
|
||||
|
||||
// If probing finds an entry in the dictionary check that the value
|
||||
// is a normal property that is not read only.
|
||||
__ bind(&done); // scratch2 == elements + 4 * index
|
||||
const int kElementsStartOffset = StringDictionary::kHeaderSize +
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
const int kElementsStartOffset = NameDictionary::kHeaderSize +
|
||||
NameDictionary::kElementsStartIndex * kPointerSize;
|
||||
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
|
||||
const int kTypeAndReadOnlyMask =
|
||||
(PropertyDetails::TypeField::kMask |
|
||||
@ -303,22 +303,25 @@ static void GenerateFastArrayLoad(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Checks whether a key is an array index string or an internalized string.
|
||||
// Falls through if a key is an internalized string.
|
||||
static void GenerateKeyStringCheck(MacroAssembler* masm,
|
||||
Register key,
|
||||
Register map,
|
||||
Register hash,
|
||||
Label* index_string,
|
||||
Label* not_internalized) {
|
||||
// Checks whether a key is an array index string or a unique name.
|
||||
// Falls through if a key is a unique name.
|
||||
static void GenerateKeyNameCheck(MacroAssembler* masm,
|
||||
Register key,
|
||||
Register map,
|
||||
Register hash,
|
||||
Label* index_string,
|
||||
Label* not_unique) {
|
||||
// The key is not a smi.
|
||||
// Is it a string?
|
||||
__ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE);
|
||||
__ b(ge, not_internalized);
|
||||
Label unique;
|
||||
// Is it a name?
|
||||
__ CompareObjectType(key, map, hash, LAST_UNIQUE_NAME_TYPE);
|
||||
__ b(hi, not_unique);
|
||||
STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
|
||||
__ b(eq, &unique);
|
||||
|
||||
// Is the string an array index, with cached numeric value?
|
||||
__ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
|
||||
__ tst(hash, Operand(String::kContainsCachedArrayIndexMask));
|
||||
__ ldr(hash, FieldMemOperand(key, Name::kHashFieldOffset));
|
||||
__ tst(hash, Operand(Name::kContainsCachedArrayIndexMask));
|
||||
__ b(eq, index_string);
|
||||
|
||||
// Is the string internalized?
|
||||
@ -326,7 +329,9 @@ static void GenerateKeyStringCheck(MacroAssembler* masm,
|
||||
__ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
|
||||
STATIC_ASSERT(kInternalizedTag != 0);
|
||||
__ tst(hash, Operand(kIsInternalizedMask));
|
||||
__ b(eq, not_internalized);
|
||||
__ b(eq, not_unique);
|
||||
|
||||
__ bind(&unique);
|
||||
}
|
||||
|
||||
|
||||
@ -427,7 +432,7 @@ void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
|
||||
// Get the receiver of the function from the stack into r1.
|
||||
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
|
||||
|
||||
GenerateStringDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
|
||||
GenerateNameDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
|
||||
|
||||
// r0: elements
|
||||
// Search the dictionary - put result in register r1.
|
||||
@ -531,11 +536,11 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
|
||||
|
||||
Label do_call, slow_call, slow_load, slow_reload_receiver;
|
||||
Label check_number_dictionary, check_string, lookup_monomorphic_cache;
|
||||
Label index_smi, index_string;
|
||||
Label check_number_dictionary, check_name, lookup_monomorphic_cache;
|
||||
Label index_smi, index_name;
|
||||
|
||||
// Check that the key is a smi.
|
||||
__ JumpIfNotSmi(r2, &check_string);
|
||||
__ JumpIfNotSmi(r2, &check_name);
|
||||
__ bind(&index_smi);
|
||||
// Now the key is known to be a smi. This place is also jumped to from below
|
||||
// where a numeric string is converted to a smi.
|
||||
@ -582,10 +587,10 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
__ mov(r1, r0);
|
||||
__ jmp(&do_call);
|
||||
|
||||
__ bind(&check_string);
|
||||
GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
|
||||
__ bind(&check_name);
|
||||
GenerateKeyNameCheck(masm, r2, r0, r3, &index_name, &slow_call);
|
||||
|
||||
// The key is known to be internalized.
|
||||
// The key is known to be a unique name.
|
||||
// If the receiver is a regular JS object with slow properties then do
|
||||
// a quick inline probe of the receiver's dictionary.
|
||||
// Otherwise do the monomorphic cache probe.
|
||||
@ -613,14 +618,14 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
__ bind(&slow_call);
|
||||
// This branch is taken if:
|
||||
// - the receiver requires boxing or access check,
|
||||
// - the key is neither smi nor an internalized string,
|
||||
// - the key is neither smi nor a unique name,
|
||||
// - the value loaded is not a function,
|
||||
// - there is hope that the runtime will create a monomorphic call stub
|
||||
// that will get fetched next time.
|
||||
__ IncrementCounter(counters->keyed_call_generic_slow(), 1, r0, r3);
|
||||
GenerateMiss(masm, argc);
|
||||
|
||||
__ bind(&index_string);
|
||||
__ bind(&index_name);
|
||||
__ IndexFromHash(r3, r2);
|
||||
// Now jump to the place where smi keys are handled.
|
||||
__ jmp(&index_smi);
|
||||
@ -633,10 +638,10 @@ void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
|
||||
// -- lr : return address
|
||||
// -----------------------------------
|
||||
|
||||
// Check if the name is a string.
|
||||
// Check if the name is really a name.
|
||||
Label miss;
|
||||
__ JumpIfSmi(r2, &miss);
|
||||
__ IsObjectJSStringType(r2, r0, &miss);
|
||||
__ IsObjectNameType(r2, r0, &miss);
|
||||
|
||||
CallICBase::GenerateNormal(masm, argc);
|
||||
__ bind(&miss);
|
||||
@ -675,7 +680,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
||||
// -----------------------------------
|
||||
Label miss;
|
||||
|
||||
GenerateStringDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
|
||||
GenerateNameDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
|
||||
|
||||
// r1: elements
|
||||
GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
|
||||
@ -918,7 +923,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
// -- r0 : key
|
||||
// -- r1 : receiver
|
||||
// -----------------------------------
|
||||
Label slow, check_string, index_smi, index_string, property_array_property;
|
||||
Label slow, check_name, index_smi, index_name, property_array_property;
|
||||
Label probe_dictionary, check_number_dictionary;
|
||||
|
||||
Register key = r0;
|
||||
@ -927,7 +932,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
Isolate* isolate = masm->isolate();
|
||||
|
||||
// Check that the key is a smi.
|
||||
__ JumpIfNotSmi(key, &check_string);
|
||||
__ JumpIfNotSmi(key, &check_name);
|
||||
__ bind(&index_smi);
|
||||
// Now the key is known to be a smi. This place is also jumped to from below
|
||||
// where a numeric string is converted to a smi.
|
||||
@ -964,8 +969,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
1, r2, r3);
|
||||
GenerateRuntimeGetProperty(masm);
|
||||
|
||||
__ bind(&check_string);
|
||||
GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
|
||||
__ bind(&check_name);
|
||||
GenerateKeyNameCheck(masm, key, r2, r3, &index_name, &slow);
|
||||
|
||||
GenerateKeyedLoadReceiverCheck(
|
||||
masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
|
||||
@ -979,15 +984,15 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ b(eq, &probe_dictionary);
|
||||
|
||||
// Load the map of the receiver, compute the keyed lookup cache hash
|
||||
// based on 32 bits of the map pointer and the string hash.
|
||||
// based on 32 bits of the map pointer and the name hash.
|
||||
__ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
|
||||
__ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
|
||||
__ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
|
||||
__ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
|
||||
__ ldr(r4, FieldMemOperand(r0, Name::kHashFieldOffset));
|
||||
__ eor(r3, r3, Operand(r4, ASR, Name::kHashShift));
|
||||
int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask;
|
||||
__ And(r3, r3, Operand(mask));
|
||||
|
||||
// Load the key (consisting of map and internalized string) from the cache and
|
||||
// Load the key (consisting of map and unique name) from the cache and
|
||||
// check for match.
|
||||
Label load_in_object_property;
|
||||
static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
|
||||
@ -1004,13 +1009,13 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ ldr(r5, MemOperand(r4, kPointerSize * 2, PostIndex));
|
||||
__ cmp(r2, r5);
|
||||
__ b(ne, &try_next_entry);
|
||||
__ ldr(r5, MemOperand(r4, -kPointerSize)); // Load string
|
||||
__ ldr(r5, MemOperand(r4, -kPointerSize)); // Load name
|
||||
__ cmp(r0, r5);
|
||||
__ b(eq, &hit_on_nth_entry[i]);
|
||||
__ bind(&try_next_entry);
|
||||
}
|
||||
|
||||
// Last entry: Load map and move r4 to string.
|
||||
// Last entry: Load map and move r4 to name.
|
||||
__ ldr(r5, MemOperand(r4, kPointerSize, PostIndex));
|
||||
__ cmp(r2, r5);
|
||||
__ b(ne, &slow);
|
||||
@ -1076,7 +1081,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
isolate->counters()->keyed_load_generic_symbol(), 1, r2, r3);
|
||||
__ Ret();
|
||||
|
||||
__ bind(&index_string);
|
||||
__ bind(&index_name);
|
||||
__ IndexFromHash(r3, key);
|
||||
// Now jump to the place where smi keys are handled.
|
||||
__ jmp(&index_smi);
|
||||
@ -1547,7 +1552,7 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
|
||||
// -----------------------------------
|
||||
Label miss;
|
||||
|
||||
GenerateStringDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
|
||||
GenerateNameDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
|
||||
|
||||
GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
|
||||
Counters* counters = masm->isolate()->counters();
|
||||
|
@ -1225,6 +1225,16 @@ void MacroAssembler::IsObjectJSStringType(Register object,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsObjectNameType(Register object,
|
||||
Register scratch,
|
||||
Label* fail) {
|
||||
ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
|
||||
ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
|
||||
cmp(scratch, Operand(LAST_NAME_TYPE));
|
||||
b(hi, fail);
|
||||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
void MacroAssembler::DebugBreak() {
|
||||
mov(r0, Operand::Zero());
|
||||
@ -3196,6 +3206,20 @@ void MacroAssembler::AssertString(Register object) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::AssertName(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
tst(object, Operand(kSmiTagMask));
|
||||
Check(ne, "Operand is a smi and not a name");
|
||||
push(object);
|
||||
ldr(object, FieldMemOperand(object, HeapObject::kMapOffset));
|
||||
CompareInstanceType(object, object, LAST_NAME_TYPE);
|
||||
pop(object);
|
||||
Check(le, "Operand is not a name");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MacroAssembler::AssertRootValue(Register src,
|
||||
Heap::RootListIndex root_value_index,
|
||||
|
@ -578,6 +578,10 @@ class MacroAssembler: public Assembler {
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
||||
void IsObjectNameType(Register object,
|
||||
Register scratch,
|
||||
Label* fail);
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
// ---------------------------------------------------------------------------
|
||||
// Debugger Support
|
||||
@ -1221,9 +1225,12 @@ class MacroAssembler: public Assembler {
|
||||
void AssertNotSmi(Register object);
|
||||
void AssertSmi(Register object);
|
||||
|
||||
// Abort execution if argument is a string, enabled via --debug-code.
|
||||
// Abort execution if argument is not a string, enabled via --debug-code.
|
||||
void AssertString(Register object);
|
||||
|
||||
// Abort execution if argument is not a name, enabled via --debug-code.
|
||||
void AssertName(Register object);
|
||||
|
||||
// Abort execution if argument is not the root value with the given index,
|
||||
// enabled via --debug-code.
|
||||
void AssertRootValue(Register src,
|
||||
|
@ -130,14 +130,14 @@ static void ProbeTable(Isolate* isolate,
|
||||
// the property. This function may return false negatives, so miss_label
|
||||
// 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 internalized and receiver must be a heap object.
|
||||
// Name must be unique and receiver must be a heap object.
|
||||
static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
|
||||
Label* miss_label,
|
||||
Register receiver,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register scratch0,
|
||||
Register scratch1) {
|
||||
ASSERT(name->IsInternalizedString());
|
||||
ASSERT(name->IsUniqueName());
|
||||
Counters* counters = masm->isolate()->counters();
|
||||
__ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
|
||||
__ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
|
||||
@ -173,13 +173,13 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
|
||||
__ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
|
||||
|
||||
|
||||
StringDictionaryLookupStub::GenerateNegativeLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
receiver,
|
||||
properties,
|
||||
name,
|
||||
scratch1);
|
||||
NameDictionaryLookupStub::GenerateNegativeLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
receiver,
|
||||
properties,
|
||||
name,
|
||||
scratch1);
|
||||
__ bind(&done);
|
||||
__ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
|
||||
}
|
||||
@ -228,7 +228,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
__ JumpIfSmi(receiver, &miss);
|
||||
|
||||
// Get the map of the receiver and compute the hash.
|
||||
__ ldr(scratch, FieldMemOperand(name, String::kHashFieldOffset));
|
||||
__ ldr(scratch, FieldMemOperand(name, Name::kHashFieldOffset));
|
||||
__ ldr(ip, FieldMemOperand(receiver, HeapObject::kMapOffset));
|
||||
__ add(scratch, scratch, Operand(ip));
|
||||
uint32_t mask = kPrimaryTableSize - 1;
|
||||
@ -443,7 +443,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
|
||||
Handle<JSObject> object,
|
||||
int index,
|
||||
Handle<Map> transition,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register receiver_reg,
|
||||
Register name_reg,
|
||||
Register scratch1,
|
||||
@ -774,7 +774,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
void Compile(MacroAssembler* masm,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
LookupResult* lookup,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
@ -805,7 +805,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
Register scratch3,
|
||||
Handle<JSObject> interceptor_holder,
|
||||
LookupResult* lookup,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
const CallOptimization& optimization,
|
||||
Label* miss_label) {
|
||||
ASSERT(optimization.is_constant_call());
|
||||
@ -899,7 +899,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Register scratch3,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> interceptor_holder,
|
||||
Label* miss_label) {
|
||||
Register holder =
|
||||
@ -956,7 +956,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
// property.
|
||||
static void GenerateCheckPropertyCell(MacroAssembler* masm,
|
||||
Handle<GlobalObject> global,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register scratch,
|
||||
Label* miss) {
|
||||
Handle<JSGlobalPropertyCell> cell =
|
||||
@ -976,7 +976,7 @@ static void GenerateCheckPropertyCell(MacroAssembler* masm,
|
||||
static void GenerateCheckPropertyCells(MacroAssembler* masm,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register scratch,
|
||||
Label* miss) {
|
||||
Handle<JSObject> current = object;
|
||||
@ -1078,7 +1078,7 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
|
||||
Register holder_reg,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
int save_at_depth,
|
||||
Label* miss,
|
||||
PrototypeCheckType check) {
|
||||
@ -1110,11 +1110,12 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
|
||||
if (!current->HasFastProperties() &&
|
||||
!current->IsJSGlobalObject() &&
|
||||
!current->IsJSGlobalProxy()) {
|
||||
if (!name->IsInternalizedString()) {
|
||||
name = factory()->InternalizeString(name);
|
||||
if (!name->IsUniqueName()) {
|
||||
ASSERT(name->IsString());
|
||||
name = factory()->InternalizeString(Handle<String>::cast(name));
|
||||
}
|
||||
ASSERT(current->property_dictionary()->FindEntry(*name) ==
|
||||
StringDictionary::kNotFound);
|
||||
NameDictionary::kNotFound);
|
||||
|
||||
GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
|
||||
scratch1, scratch2);
|
||||
@ -1198,7 +1199,7 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend(
|
||||
Handle<JSObject> object,
|
||||
Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* success,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
Label miss;
|
||||
@ -1216,20 +1217,20 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend(
|
||||
|
||||
// Probe the dictionary.
|
||||
Label probe_done;
|
||||
StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
|
||||
&miss,
|
||||
&probe_done,
|
||||
dictionary,
|
||||
this->name(),
|
||||
scratch2(),
|
||||
scratch3());
|
||||
NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
|
||||
&miss,
|
||||
&probe_done,
|
||||
dictionary,
|
||||
this->name(),
|
||||
scratch2(),
|
||||
scratch3());
|
||||
__ bind(&probe_done);
|
||||
|
||||
// If probing finds an entry in the dictionary, scratch3 contains the
|
||||
// pointer into the dictionary. Check that the value is the callback.
|
||||
Register pointer = scratch3();
|
||||
const int kElementsStartOffset = StringDictionary::kHeaderSize +
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
const int kElementsStartOffset = NameDictionary::kHeaderSize +
|
||||
NameDictionary::kElementsStartIndex * kPointerSize;
|
||||
const int kValueOffset = kElementsStartOffset + kPointerSize;
|
||||
__ ldr(scratch2(), FieldMemOperand(pointer, kValueOffset));
|
||||
__ cmp(scratch2(), Operand(callback));
|
||||
@ -1244,7 +1245,7 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend(
|
||||
void BaseLoadStubCompiler::NonexistentHandlerFrontend(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> last,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* success,
|
||||
Handle<GlobalObject> global) {
|
||||
Label miss;
|
||||
@ -1301,7 +1302,7 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
|
||||
__ Push(reg, scratch3());
|
||||
__ mov(scratch3(), Operand(ExternalReference::isolate_address()));
|
||||
__ Push(scratch3(), name());
|
||||
__ mov(r0, sp); // r0 = Handle<String>
|
||||
__ mov(r0, sp); // r0 = Handle<Name>
|
||||
|
||||
const int kApiStackSpace = 1;
|
||||
FrameScope frame_scope(masm(), StackFrame::MANUAL);
|
||||
@ -1328,7 +1329,7 @@ void BaseLoadStubCompiler::GenerateLoadInterceptor(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> interceptor_holder,
|
||||
LookupResult* lookup,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
ASSERT(interceptor_holder->HasNamedInterceptor());
|
||||
ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
|
||||
|
||||
@ -1412,7 +1413,7 @@ void BaseLoadStubCompiler::GenerateLoadInterceptor(
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
|
||||
void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
|
||||
if (kind_ == Code::KEYED_CALL_IC) {
|
||||
__ cmp(r2, Operand(name));
|
||||
__ b(ne, miss);
|
||||
@ -1422,7 +1423,7 @@ void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
|
||||
|
||||
void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* miss) {
|
||||
ASSERT(holder->IsGlobalObject());
|
||||
|
||||
@ -1480,7 +1481,7 @@ void CallStubCompiler::GenerateMissBranch() {
|
||||
Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
PropertyIndex index,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r2 : name
|
||||
// -- lr : return address
|
||||
@ -2397,7 +2398,7 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
|
||||
|
||||
void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
CheckType check,
|
||||
Label* success) {
|
||||
// ----------- S t a t e -------------
|
||||
@ -2509,13 +2510,13 @@ void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
|
||||
Handle<Code> CallStubCompiler::CompileCallConstant(
|
||||
Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
CheckType check,
|
||||
Handle<JSFunction> function) {
|
||||
if (HasCustomCallGenerator(function)) {
|
||||
Handle<Code> code = CompileCustomCall(object, holder,
|
||||
Handle<JSGlobalPropertyCell>::null(),
|
||||
function, name);
|
||||
function, Handle<String>::cast(name));
|
||||
// A null handle means bail out to the regular compiler code below.
|
||||
if (!code.is_null()) return code;
|
||||
}
|
||||
@ -2526,7 +2527,6 @@ Handle<Code> CallStubCompiler::CompileCallConstant(
|
||||
__ bind(&success);
|
||||
CompileHandlerBackend(function);
|
||||
|
||||
|
||||
// Return the generated code.
|
||||
return GetCode(function);
|
||||
}
|
||||
@ -2534,7 +2534,7 @@ Handle<Code> CallStubCompiler::CompileCallConstant(
|
||||
|
||||
Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r2 : name
|
||||
// -- lr : return address
|
||||
@ -2575,13 +2575,14 @@ Handle<Code> CallStubCompiler::CompileCallGlobal(
|
||||
Handle<GlobalObject> holder,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
Handle<JSFunction> function,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r2 : name
|
||||
// -- lr : return address
|
||||
// -----------------------------------
|
||||
if (HasCustomCallGenerator(function)) {
|
||||
Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
|
||||
Handle<Code> code = CompileCustomCall(
|
||||
object, holder, cell, function, Handle<String>::cast(name));
|
||||
// A null handle means bail out to the regular compiler code below.
|
||||
if (!code.is_null()) return code;
|
||||
}
|
||||
@ -2631,7 +2632,7 @@ Handle<Code> CallStubCompiler::CompileCallGlobal(
|
||||
Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
|
||||
int index,
|
||||
Handle<Map> transition,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : value
|
||||
// -- r1 : receiver
|
||||
@ -2659,7 +2660,7 @@ Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
|
||||
|
||||
|
||||
Handle<Code> StoreStubCompiler::CompileStoreCallback(
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
@ -2743,7 +2744,7 @@ void StoreStubCompiler::GenerateStoreViaSetter(
|
||||
|
||||
|
||||
Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> setter) {
|
||||
@ -2772,7 +2773,7 @@ Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
|
||||
|
||||
Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
|
||||
Handle<JSObject> receiver,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : value
|
||||
// -- r1 : receiver
|
||||
@ -2818,7 +2819,7 @@ Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
|
||||
Handle<Code> StoreStubCompiler::CompileStoreGlobal(
|
||||
Handle<GlobalObject> object,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : value
|
||||
// -- r1 : receiver
|
||||
@ -2864,7 +2865,7 @@ Handle<Code> StoreStubCompiler::CompileStoreGlobal(
|
||||
Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> last,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<GlobalObject> global) {
|
||||
Label success;
|
||||
|
||||
@ -2895,7 +2896,7 @@ Register* KeyedLoadStubCompiler::registers() {
|
||||
}
|
||||
|
||||
|
||||
void KeyedLoadStubCompiler::GenerateNameCheck(Handle<String> name,
|
||||
void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
|
||||
Register name_reg,
|
||||
Label* miss) {
|
||||
__ cmp(name_reg, Operand(name));
|
||||
@ -2944,7 +2945,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
|
||||
Handle<JSObject> object,
|
||||
Handle<GlobalObject> global,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
bool is_dont_delete) {
|
||||
Label success, miss;
|
||||
|
||||
@ -3008,7 +3009,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
|
||||
Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
|
||||
MapHandleList* receiver_maps,
|
||||
CodeHandleList* handlers,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Code::StubType type,
|
||||
IcCheckType check) {
|
||||
Label miss;
|
||||
@ -3041,7 +3042,7 @@ Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
|
||||
Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
|
||||
int index,
|
||||
Handle<Map> transition,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : value
|
||||
// -- r1 : name
|
||||
|
@ -2294,7 +2294,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
|
||||
switch (details.type()) {
|
||||
case FIELD: {
|
||||
HandleScope inner(isolate());
|
||||
Handle<String> key = Handle<String>(descs->GetKey(i));
|
||||
Handle<Name> key = Handle<Name>(descs->GetKey(i));
|
||||
int index = descs->GetFieldIndex(i);
|
||||
Handle<Object> value = Handle<Object>(from->FastPropertyAt(index),
|
||||
isolate());
|
||||
@ -2305,7 +2305,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
|
||||
}
|
||||
case CONSTANT_FUNCTION: {
|
||||
HandleScope inner(isolate());
|
||||
Handle<String> key = Handle<String>(descs->GetKey(i));
|
||||
Handle<Name> key = Handle<Name>(descs->GetKey(i));
|
||||
Handle<JSFunction> fun =
|
||||
Handle<JSFunction>(descs->GetConstantFunction(i));
|
||||
CHECK_NOT_EMPTY_HANDLE(isolate(),
|
||||
@ -2321,7 +2321,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
|
||||
HandleScope inner(isolate());
|
||||
ASSERT(!to->HasFastProperties());
|
||||
// Add to dictionary.
|
||||
Handle<String> key = Handle<String>(descs->GetKey(i));
|
||||
Handle<Name> key = Handle<Name>(descs->GetKey(i));
|
||||
Handle<Object> callbacks(descs->GetCallbacksObject(i), isolate());
|
||||
PropertyDetails d = PropertyDetails(details.attributes(),
|
||||
CALLBACKS,
|
||||
@ -2341,19 +2341,19 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Handle<StringDictionary> properties =
|
||||
Handle<StringDictionary>(from->property_dictionary());
|
||||
Handle<NameDictionary> properties =
|
||||
Handle<NameDictionary>(from->property_dictionary());
|
||||
int capacity = properties->Capacity();
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* raw_key(properties->KeyAt(i));
|
||||
if (properties->IsKey(raw_key)) {
|
||||
ASSERT(raw_key->IsString());
|
||||
ASSERT(raw_key->IsName());
|
||||
// If the property is already there we skip it.
|
||||
LookupResult result(isolate());
|
||||
to->LocalLookup(String::cast(raw_key), &result);
|
||||
to->LocalLookup(Name::cast(raw_key), &result);
|
||||
if (result.IsFound()) continue;
|
||||
// Set the property.
|
||||
Handle<String> key = Handle<String>(String::cast(raw_key));
|
||||
Handle<Name> key = Handle<Name>(Name::cast(raw_key));
|
||||
Handle<Object> value = Handle<Object>(properties->ValueAt(i),
|
||||
isolate());
|
||||
if (value->IsJSGlobalPropertyCell()) {
|
||||
|
@ -78,7 +78,7 @@ namespace internal {
|
||||
V(ArrayNArgumentsConstructor) \
|
||||
V(KeyedStoreElement) \
|
||||
V(DebuggerStatement) \
|
||||
V(StringDictionaryLookup) \
|
||||
V(NameDictionaryLookup) \
|
||||
V(ElementsTransitionAndStore) \
|
||||
V(TransitionElementsKind) \
|
||||
V(StoreArrayLiteralElement) \
|
||||
|
@ -63,7 +63,7 @@ ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator,
|
||||
|
||||
void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag,
|
||||
const char* prefix,
|
||||
String* name,
|
||||
Name* name,
|
||||
Address start) {
|
||||
if (FilterOutCodeCreateEvent(tag)) return;
|
||||
CodeEventsContainer evt_rec;
|
||||
@ -79,7 +79,7 @@ void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag,
|
||||
|
||||
|
||||
void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
|
||||
String* name,
|
||||
Name* name,
|
||||
String* resource_name,
|
||||
int line_number,
|
||||
Address start,
|
||||
@ -372,7 +372,7 @@ bool CpuProfiler::HasDetachedProfiles() {
|
||||
}
|
||||
|
||||
|
||||
void CpuProfiler::CallbackEvent(String* name, Address entry_point) {
|
||||
void CpuProfiler::CallbackEvent(Name* name, Address entry_point) {
|
||||
Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
|
||||
Logger::CALLBACK_TAG, CodeEntry::kEmptyNamePrefix, name, entry_point);
|
||||
}
|
||||
@ -386,7 +386,7 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
|
||||
|
||||
|
||||
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
|
||||
Code* code, String* name) {
|
||||
Code* code, Name* name) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
isolate->cpu_profiler()->processor_->CodeCreateEvent(
|
||||
tag,
|
||||
@ -402,7 +402,7 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
|
||||
void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
|
||||
Code* code,
|
||||
SharedFunctionInfo* shared,
|
||||
String* name) {
|
||||
Name* name) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
isolate->cpu_profiler()->processor_->CodeCreateEvent(
|
||||
tag,
|
||||
@ -455,7 +455,7 @@ void CpuProfiler::SharedFunctionInfoMoveEvent(Address from, Address to) {
|
||||
}
|
||||
|
||||
|
||||
void CpuProfiler::GetterCallbackEvent(String* name, Address entry_point) {
|
||||
void CpuProfiler::GetterCallbackEvent(Name* name, Address entry_point) {
|
||||
Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
|
||||
Logger::CALLBACK_TAG, "get ", name, entry_point);
|
||||
}
|
||||
@ -471,7 +471,7 @@ void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
|
||||
}
|
||||
|
||||
|
||||
void CpuProfiler::SetterCallbackEvent(String* name, Address entry_point) {
|
||||
void CpuProfiler::SetterCallbackEvent(Name* name, Address entry_point) {
|
||||
Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
|
||||
Logger::CALLBACK_TAG, "set ", name, entry_point);
|
||||
}
|
||||
|
@ -136,10 +136,10 @@ class ProfilerEventsProcessor : public Thread {
|
||||
|
||||
// Events adding methods. Called by VM threads.
|
||||
void CallbackCreateEvent(Logger::LogEventsAndTags tag,
|
||||
const char* prefix, String* name,
|
||||
const char* prefix, Name* name,
|
||||
Address start);
|
||||
void CodeCreateEvent(Logger::LogEventsAndTags tag,
|
||||
String* name,
|
||||
Name* name,
|
||||
String* resource_name, int line_number,
|
||||
Address start, unsigned size,
|
||||
Address shared);
|
||||
@ -229,15 +229,15 @@ class CpuProfiler {
|
||||
|
||||
// Must be called via PROFILE macro, otherwise will crash when
|
||||
// profiling is not enabled.
|
||||
static void CallbackEvent(String* name, Address entry_point);
|
||||
static void CallbackEvent(Name* name, Address entry_point);
|
||||
static void CodeCreateEvent(Logger::LogEventsAndTags tag,
|
||||
Code* code, const char* comment);
|
||||
static void CodeCreateEvent(Logger::LogEventsAndTags tag,
|
||||
Code* code, String* name);
|
||||
Code* code, Name* name);
|
||||
static void CodeCreateEvent(Logger::LogEventsAndTags tag,
|
||||
Code* code,
|
||||
SharedFunctionInfo* shared,
|
||||
String* name);
|
||||
Name* name);
|
||||
static void CodeCreateEvent(Logger::LogEventsAndTags tag,
|
||||
Code* code,
|
||||
SharedFunctionInfo* shared,
|
||||
@ -247,9 +247,9 @@ class CpuProfiler {
|
||||
static void CodeMovingGCEvent() {}
|
||||
static void CodeMoveEvent(Address from, Address to);
|
||||
static void CodeDeleteEvent(Address from);
|
||||
static void GetterCallbackEvent(String* name, Address entry_point);
|
||||
static void GetterCallbackEvent(Name* name, Address entry_point);
|
||||
static void RegExpCodeCreateEvent(Code* code, String* source);
|
||||
static void SetterCallbackEvent(String* name, Address entry_point);
|
||||
static void SetterCallbackEvent(Name* name, Address entry_point);
|
||||
static void SharedFunctionInfoMoveEvent(Address from, Address to);
|
||||
|
||||
static INLINE(bool is_profiling(Isolate* isolate)) {
|
||||
|
@ -70,11 +70,11 @@ Handle<FixedDoubleArray> Factory::NewFixedDoubleArray(int size,
|
||||
}
|
||||
|
||||
|
||||
Handle<StringDictionary> Factory::NewStringDictionary(int at_least_space_for) {
|
||||
Handle<NameDictionary> Factory::NewNameDictionary(int at_least_space_for) {
|
||||
ASSERT(0 <= at_least_space_for);
|
||||
CALL_HEAP_FUNCTION(isolate(),
|
||||
StringDictionary::Allocate(at_least_space_for),
|
||||
StringDictionary);
|
||||
NameDictionary::Allocate(at_least_space_for),
|
||||
NameDictionary);
|
||||
}
|
||||
|
||||
|
||||
|
@ -60,7 +60,7 @@ class Factory {
|
||||
Handle<UnseededNumberDictionary> NewUnseededNumberDictionary(
|
||||
int at_least_space_for);
|
||||
|
||||
Handle<StringDictionary> NewStringDictionary(int at_least_space_for);
|
||||
Handle<NameDictionary> NewNameDictionary(int at_least_space_for);
|
||||
|
||||
Handle<ObjectHashSet> NewObjectHashSet(int at_least_space_for);
|
||||
|
||||
|
@ -260,7 +260,7 @@ Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
|
||||
|
||||
|
||||
Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object,
|
||||
Handle<String> key,
|
||||
Handle<Name> key,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes,
|
||||
StrictModeFlag strict_mode) {
|
||||
@ -291,7 +291,7 @@ Handle<Object> GetProperty(Isolate* isolate,
|
||||
|
||||
Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
PropertyAttributes* attributes) {
|
||||
Isolate* isolate = receiver->GetIsolate();
|
||||
CALL_HEAP_FUNCTION(isolate,
|
||||
@ -625,7 +625,7 @@ static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
|
||||
int len = array->length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
Object* e = array->get(i);
|
||||
if (!(e->IsString() || e->IsNumber())) return false;
|
||||
if (!(e->IsName() || e->IsNumber())) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -831,7 +831,7 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
|
||||
|
||||
return ReduceFixedArrayTo(storage, enum_size);
|
||||
} else {
|
||||
Handle<StringDictionary> dictionary(object->property_dictionary());
|
||||
Handle<NameDictionary> dictionary(object->property_dictionary());
|
||||
|
||||
int length = dictionary->NumberOfElements();
|
||||
if (length == 0) {
|
||||
@ -852,7 +852,7 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
|
||||
// many properties were added but subsequently deleted.
|
||||
int next_enumeration = dictionary->NextEnumerationIndex();
|
||||
if (!object->IsGlobalObject() && next_enumeration > (length * 3) / 2) {
|
||||
StringDictionary::DoGenerateNewEnumerationIndices(dictionary);
|
||||
NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
|
||||
next_enumeration = dictionary->NextEnumerationIndex();
|
||||
}
|
||||
|
||||
|
@ -1320,7 +1320,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
|
||||
case FIELD: {
|
||||
int index = descs->GetFieldIndex(i);
|
||||
|
||||
String* k = descs->GetKey(i);
|
||||
Name* k = descs->GetKey(i);
|
||||
if (index < js_obj->map()->inobject_properties()) {
|
||||
Object* value = js_obj->InObjectPropertyAt(index);
|
||||
if (k != heap_->hidden_string()) {
|
||||
@ -1378,7 +1378,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
StringDictionary* dictionary = js_obj->property_dictionary();
|
||||
NameDictionary* dictionary = js_obj->property_dictionary();
|
||||
int length = dictionary->Capacity();
|
||||
for (int i = 0; i < length; ++i) {
|
||||
Object* k = dictionary->KeyAt(i);
|
||||
@ -1688,19 +1688,20 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
|
||||
|
||||
void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
|
||||
int parent_entry,
|
||||
String* reference_name,
|
||||
Name* reference_name,
|
||||
Object* child_obj,
|
||||
const char* name_format_string,
|
||||
int field_offset) {
|
||||
HeapEntry* child_entry = GetEntry(child_obj);
|
||||
if (child_entry != NULL) {
|
||||
HeapGraphEdge::Type type = reference_name->length() > 0 ?
|
||||
HeapGraphEdge::kProperty : HeapGraphEdge::kInternal;
|
||||
const char* name = name_format_string != NULL ?
|
||||
collection_->names()->GetFormatted(
|
||||
name_format_string,
|
||||
*reference_name->ToCString(DISALLOW_NULLS,
|
||||
ROBUST_STRING_TRAVERSAL)) :
|
||||
HeapGraphEdge::Type type =
|
||||
reference_name->IsSymbol() || String::cast(reference_name)->length() > 0
|
||||
? HeapGraphEdge::kProperty : HeapGraphEdge::kInternal;
|
||||
const char* name = name_format_string != NULL && reference_name->IsString()
|
||||
? collection_->names()->GetFormatted(
|
||||
name_format_string,
|
||||
*String::cast(reference_name)->ToCString(
|
||||
DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)) :
|
||||
collection_->names()->GetName(reference_name);
|
||||
|
||||
filler_->SetNamedReference(type,
|
||||
|
@ -512,7 +512,7 @@ class V8HeapExplorer : public HeapEntriesAllocator {
|
||||
int field_offset);
|
||||
void SetPropertyReference(HeapObject* parent_obj,
|
||||
int parent,
|
||||
String* reference_name,
|
||||
Name* reference_name,
|
||||
Object* child,
|
||||
const char* name_format_string = NULL,
|
||||
int field_offset = -1);
|
||||
|
80
src/heap.cc
80
src/heap.cc
@ -2865,14 +2865,14 @@ bool Heap::CreateInitialObjects() {
|
||||
CreateFixedStubs();
|
||||
|
||||
// Allocate the dictionary of intrinsic function names.
|
||||
{ MaybeObject* maybe_obj = StringDictionary::Allocate(Runtime::kNumFunctions);
|
||||
{ MaybeObject* maybe_obj = NameDictionary::Allocate(Runtime::kNumFunctions);
|
||||
if (!maybe_obj->ToObject(&obj)) return false;
|
||||
}
|
||||
{ MaybeObject* maybe_obj = Runtime::InitializeIntrinsicFunctionNames(this,
|
||||
obj);
|
||||
if (!maybe_obj->ToObject(&obj)) return false;
|
||||
}
|
||||
set_intrinsic_function_names(StringDictionary::cast(obj));
|
||||
set_intrinsic_function_names(NameDictionary::cast(obj));
|
||||
|
||||
{ MaybeObject* maybe_obj = AllocateInitialNumberStringCache();
|
||||
if (!maybe_obj->ToObject(&obj)) return false;
|
||||
@ -4066,9 +4066,9 @@ MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) {
|
||||
static bool HasDuplicates(DescriptorArray* descriptors) {
|
||||
int count = descriptors->number_of_descriptors();
|
||||
if (count > 1) {
|
||||
String* prev_key = descriptors->GetKey(0);
|
||||
Name* prev_key = descriptors->GetKey(0);
|
||||
for (int i = 1; i != count; i++) {
|
||||
String* current_key = descriptors->GetKey(i);
|
||||
Name* current_key = descriptors->GetKey(i);
|
||||
if (prev_key == current_key) return true;
|
||||
prev_key = current_key;
|
||||
}
|
||||
@ -4521,9 +4521,9 @@ MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
|
||||
int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
|
||||
|
||||
// Allocate a dictionary object for backing storage.
|
||||
StringDictionary* dictionary;
|
||||
NameDictionary* dictionary;
|
||||
MaybeObject* maybe_dictionary =
|
||||
StringDictionary::Allocate(
|
||||
NameDictionary::Allocate(
|
||||
map->NumberOfOwnDescriptors() * 2 + initial_size);
|
||||
if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
|
||||
|
||||
@ -7443,7 +7443,7 @@ const char* GCTracer::CollectorString() {
|
||||
}
|
||||
|
||||
|
||||
int KeyedLookupCache::Hash(Map* map, String* name) {
|
||||
int KeyedLookupCache::Hash(Map* map, Name* name) {
|
||||
// Uses only lower 32 bits if pointers are larger.
|
||||
uintptr_t addr_hash =
|
||||
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
|
||||
@ -7451,7 +7451,7 @@ int KeyedLookupCache::Hash(Map* map, String* name) {
|
||||
}
|
||||
|
||||
|
||||
int KeyedLookupCache::Lookup(Map* map, String* name) {
|
||||
int KeyedLookupCache::Lookup(Map* map, Name* name) {
|
||||
int index = (Hash(map, name) & kHashMask);
|
||||
for (int i = 0; i < kEntriesPerBucket; i++) {
|
||||
Key& key = keys_[index + i];
|
||||
@ -7463,37 +7463,43 @@ int KeyedLookupCache::Lookup(Map* map, String* name) {
|
||||
}
|
||||
|
||||
|
||||
void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
|
||||
String* internalized_name;
|
||||
if (HEAP->InternalizeStringIfExists(name, &internalized_name)) {
|
||||
int index = (Hash(map, internalized_name) & kHashMask);
|
||||
// After a GC there will be free slots, so we use them in order (this may
|
||||
// help to get the most frequently used one in position 0).
|
||||
for (int i = 0; i< kEntriesPerBucket; i++) {
|
||||
Key& key = keys_[index];
|
||||
Object* free_entry_indicator = NULL;
|
||||
if (key.map == free_entry_indicator) {
|
||||
key.map = map;
|
||||
key.name = internalized_name;
|
||||
field_offsets_[index + i] = field_offset;
|
||||
return;
|
||||
}
|
||||
void KeyedLookupCache::Update(Map* map, Name* name, int field_offset) {
|
||||
if (!name->IsUniqueName()) {
|
||||
String* internalized_string;
|
||||
if (!HEAP->InternalizeStringIfExists(
|
||||
String::cast(name), &internalized_string)) {
|
||||
return;
|
||||
}
|
||||
// No free entry found in this bucket, so we move them all down one and
|
||||
// put the new entry at position zero.
|
||||
for (int i = kEntriesPerBucket - 1; i > 0; i--) {
|
||||
Key& key = keys_[index + i];
|
||||
Key& key2 = keys_[index + i - 1];
|
||||
key = key2;
|
||||
field_offsets_[index + i] = field_offsets_[index + i - 1];
|
||||
}
|
||||
|
||||
// Write the new first entry.
|
||||
Key& key = keys_[index];
|
||||
key.map = map;
|
||||
key.name = internalized_name;
|
||||
field_offsets_[index] = field_offset;
|
||||
name = internalized_string;
|
||||
}
|
||||
|
||||
int index = (Hash(map, name) & kHashMask);
|
||||
// After a GC there will be free slots, so we use them in order (this may
|
||||
// help to get the most frequently used one in position 0).
|
||||
for (int i = 0; i< kEntriesPerBucket; i++) {
|
||||
Key& key = keys_[index];
|
||||
Object* free_entry_indicator = NULL;
|
||||
if (key.map == free_entry_indicator) {
|
||||
key.map = map;
|
||||
key.name = name;
|
||||
field_offsets_[index + i] = field_offset;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// No free entry found in this bucket, so we move them all down one and
|
||||
// put the new entry at position zero.
|
||||
for (int i = kEntriesPerBucket - 1; i > 0; i--) {
|
||||
Key& key = keys_[index + i];
|
||||
Key& key2 = keys_[index + i - 1];
|
||||
key = key2;
|
||||
field_offsets_[index + i] = field_offsets_[index + i - 1];
|
||||
}
|
||||
|
||||
// Write the new first entry.
|
||||
Key& key = keys_[index];
|
||||
key.map = map;
|
||||
key.name = name;
|
||||
field_offsets_[index] = field_offset;
|
||||
}
|
||||
|
||||
|
||||
|
22
src/heap.h
22
src/heap.h
@ -160,7 +160,7 @@ namespace internal {
|
||||
V(Object, last_script_id, LastScriptId) \
|
||||
V(Script, empty_script, EmptyScript) \
|
||||
V(Smi, real_stack_limit, RealStackLimit) \
|
||||
V(StringDictionary, intrinsic_function_names, IntrinsicFunctionNames) \
|
||||
V(NameDictionary, intrinsic_function_names, IntrinsicFunctionNames) \
|
||||
V(Smi, arguments_adaptor_deopt_pc_offset, ArgumentsAdaptorDeoptPCOffset) \
|
||||
V(Smi, construct_stub_deopt_pc_offset, ConstructStubDeoptPCOffset) \
|
||||
V(Smi, getter_stub_deopt_pc_offset, GetterStubDeoptPCOffset) \
|
||||
@ -2496,10 +2496,10 @@ class HeapIterator BASE_EMBEDDED {
|
||||
class KeyedLookupCache {
|
||||
public:
|
||||
// Lookup field offset for (map, name). If absent, -1 is returned.
|
||||
int Lookup(Map* map, String* name);
|
||||
int Lookup(Map* map, Name* name);
|
||||
|
||||
// Update an element in the cache.
|
||||
void Update(Map* map, String* name, int field_offset);
|
||||
void Update(Map* map, Name* name, int field_offset);
|
||||
|
||||
// Clear the cache.
|
||||
void Clear();
|
||||
@ -2524,7 +2524,7 @@ class KeyedLookupCache {
|
||||
}
|
||||
}
|
||||
|
||||
static inline int Hash(Map* map, String* name);
|
||||
static inline int Hash(Map* map, Name* name);
|
||||
|
||||
// Get the address of the keys and field_offsets arrays. Used in
|
||||
// generated code to perform cache lookups.
|
||||
@ -2538,7 +2538,7 @@ class KeyedLookupCache {
|
||||
|
||||
struct Key {
|
||||
Map* map;
|
||||
String* name;
|
||||
Name* name;
|
||||
};
|
||||
|
||||
Key keys_[kLength];
|
||||
@ -2558,8 +2558,8 @@ class DescriptorLookupCache {
|
||||
public:
|
||||
// Lookup descriptor index for (map, name).
|
||||
// If absent, kAbsent is returned.
|
||||
int Lookup(Map* source, String* name) {
|
||||
if (!StringShape(name).IsInternalized()) return kAbsent;
|
||||
int Lookup(Map* source, Name* name) {
|
||||
if (!name->IsUniqueName()) return kAbsent;
|
||||
int index = Hash(source, name);
|
||||
Key& key = keys_[index];
|
||||
if ((key.source == source) && (key.name == name)) return results_[index];
|
||||
@ -2567,9 +2567,9 @@ class DescriptorLookupCache {
|
||||
}
|
||||
|
||||
// Update an element in the cache.
|
||||
void Update(Map* source, String* name, int result) {
|
||||
void Update(Map* source, Name* name, int result) {
|
||||
ASSERT(result != kAbsent);
|
||||
if (StringShape(name).IsInternalized()) {
|
||||
if (name->IsUniqueName()) {
|
||||
int index = Hash(source, name);
|
||||
Key& key = keys_[index];
|
||||
key.source = source;
|
||||
@ -2592,7 +2592,7 @@ class DescriptorLookupCache {
|
||||
}
|
||||
}
|
||||
|
||||
static int Hash(Object* source, String* name) {
|
||||
static int Hash(Object* source, Name* name) {
|
||||
// Uses only lower 32 bits if pointers are larger.
|
||||
uint32_t source_hash =
|
||||
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(source))
|
||||
@ -2606,7 +2606,7 @@ class DescriptorLookupCache {
|
||||
static const int kLength = 64;
|
||||
struct Key {
|
||||
Map* source;
|
||||
String* name;
|
||||
Name* name;
|
||||
};
|
||||
|
||||
Key keys_[kLength];
|
||||
|
@ -7233,14 +7233,14 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
|
||||
// the property. This function may return false negatives, so miss_label
|
||||
// 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 an internalized string and receiver must be a heap object.
|
||||
void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register properties,
|
||||
Handle<String> name,
|
||||
Register r0) {
|
||||
ASSERT(name->IsInternalizedString());
|
||||
// Name must be a unique name and receiver must be a heap object.
|
||||
void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register properties,
|
||||
Handle<Name> name,
|
||||
Register r0) {
|
||||
ASSERT(name->IsUniqueName());
|
||||
|
||||
// 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
|
||||
@ -7255,10 +7255,10 @@ void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
__ dec(index);
|
||||
__ and_(index,
|
||||
Immediate(Smi::FromInt(name->Hash() +
|
||||
StringDictionary::GetProbeOffset(i))));
|
||||
NameDictionary::GetProbeOffset(i))));
|
||||
|
||||
// Scale the index by multiplying by the entry size.
|
||||
ASSERT(StringDictionary::kEntrySize == 3);
|
||||
ASSERT(NameDictionary::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.
|
||||
@ -7269,26 +7269,26 @@ void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
__ j(equal, done);
|
||||
|
||||
// Stop if found the property.
|
||||
__ cmp(entity_name, Handle<String>(name));
|
||||
__ cmp(entity_name, Handle<Name>(name));
|
||||
__ j(equal, miss);
|
||||
|
||||
Label the_hole;
|
||||
Label good;
|
||||
// Check for the hole and skip.
|
||||
__ cmp(entity_name, masm->isolate()->factory()->the_hole_value());
|
||||
__ j(equal, &the_hole, Label::kNear);
|
||||
__ j(equal, &good, Label::kNear);
|
||||
|
||||
// Check if the entry name is not an internalized string.
|
||||
// Check if the entry name is not a unique name.
|
||||
__ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
|
||||
__ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset),
|
||||
kIsInternalizedMask);
|
||||
__ j(zero, miss);
|
||||
__ bind(&the_hole);
|
||||
__ j(not_zero, &good);
|
||||
__ cmpb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
|
||||
static_cast<int8_t>(SYMBOL_TYPE));
|
||||
__ j(not_equal, miss);
|
||||
__ bind(&good);
|
||||
}
|
||||
|
||||
StringDictionaryLookupStub stub(properties,
|
||||
r0,
|
||||
r0,
|
||||
StringDictionaryLookupStub::NEGATIVE_LOOKUP);
|
||||
NameDictionaryLookupStub stub(properties, r0, r0, NEGATIVE_LOOKUP);
|
||||
__ push(Immediate(Handle<Object>(name)));
|
||||
__ push(Immediate(name->Hash()));
|
||||
__ CallStub(&stub);
|
||||
@ -7298,23 +7298,23 @@ void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Probe the string dictionary in the |elements| register. Jump to the
|
||||
// Probe the name dictionary in the |elements| register. Jump to the
|
||||
// |done| label if a property with the given name is found leaving the
|
||||
// index into the dictionary in |r0|. Jump to the |miss| label
|
||||
// otherwise.
|
||||
void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register elements,
|
||||
Register name,
|
||||
Register r0,
|
||||
Register r1) {
|
||||
void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register elements,
|
||||
Register name,
|
||||
Register r0,
|
||||
Register r1) {
|
||||
ASSERT(!elements.is(r0));
|
||||
ASSERT(!elements.is(r1));
|
||||
ASSERT(!name.is(r0));
|
||||
ASSERT(!name.is(r1));
|
||||
|
||||
__ AssertString(name);
|
||||
__ AssertName(name);
|
||||
|
||||
__ mov(r1, FieldOperand(elements, kCapacityOffset));
|
||||
__ shr(r1, kSmiTagSize); // convert smi to int
|
||||
@ -7325,15 +7325,15 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
// cover ~93% of loads from dictionaries.
|
||||
for (int i = 0; i < kInlinedProbes; i++) {
|
||||
// Compute the masked index: (hash + i + i * i) & mask.
|
||||
__ mov(r0, FieldOperand(name, String::kHashFieldOffset));
|
||||
__ shr(r0, String::kHashShift);
|
||||
__ mov(r0, FieldOperand(name, Name::kHashFieldOffset));
|
||||
__ shr(r0, Name::kHashShift);
|
||||
if (i > 0) {
|
||||
__ add(r0, Immediate(StringDictionary::GetProbeOffset(i)));
|
||||
__ add(r0, Immediate(NameDictionary::GetProbeOffset(i)));
|
||||
}
|
||||
__ and_(r0, r1);
|
||||
|
||||
// Scale the index by multiplying by the entry size.
|
||||
ASSERT(StringDictionary::kEntrySize == 3);
|
||||
ASSERT(NameDictionary::kEntrySize == 3);
|
||||
__ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3
|
||||
|
||||
// Check if the key is identical to the name.
|
||||
@ -7344,13 +7344,10 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
__ j(equal, done);
|
||||
}
|
||||
|
||||
StringDictionaryLookupStub stub(elements,
|
||||
r1,
|
||||
r0,
|
||||
POSITIVE_LOOKUP);
|
||||
NameDictionaryLookupStub stub(elements, r1, r0, POSITIVE_LOOKUP);
|
||||
__ push(name);
|
||||
__ mov(r0, FieldOperand(name, String::kHashFieldOffset));
|
||||
__ shr(r0, String::kHashShift);
|
||||
__ mov(r0, FieldOperand(name, Name::kHashFieldOffset));
|
||||
__ shr(r0, Name::kHashShift);
|
||||
__ push(r0);
|
||||
__ CallStub(&stub);
|
||||
|
||||
@ -7360,7 +7357,7 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
// This stub overrides SometimesSetsUpAFrame() to return false. That means
|
||||
// we cannot call anything that could cause a GC from this stub.
|
||||
// Stack frame on entry:
|
||||
@ -7368,7 +7365,7 @@ void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
// esp[1 * kPointerSize]: key's hash.
|
||||
// esp[2 * kPointerSize]: key.
|
||||
// Registers:
|
||||
// dictionary_: StringDictionary to probe.
|
||||
// dictionary_: NameDictionary to probe.
|
||||
// result_: used as scratch.
|
||||
// index_: will hold an index of entry if lookup is successful.
|
||||
// might alias with result_.
|
||||
@ -7393,12 +7390,12 @@ void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
// Compute the masked index: (hash + i + i * i) & mask.
|
||||
__ mov(scratch, Operand(esp, 2 * kPointerSize));
|
||||
if (i > 0) {
|
||||
__ add(scratch, Immediate(StringDictionary::GetProbeOffset(i)));
|
||||
__ add(scratch, Immediate(NameDictionary::GetProbeOffset(i)));
|
||||
}
|
||||
__ and_(scratch, Operand(esp, 0));
|
||||
|
||||
// Scale the index by multiplying by the entry size.
|
||||
ASSERT(StringDictionary::kEntrySize == 3);
|
||||
ASSERT(NameDictionary::kEntrySize == 3);
|
||||
__ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3.
|
||||
|
||||
// Having undefined at this place means the name is not contained.
|
||||
@ -7415,15 +7412,20 @@ void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
__ j(equal, &in_dictionary);
|
||||
|
||||
if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
|
||||
// If we hit a key that is not an internalized string during negative
|
||||
// If we hit a key that is not a unique name during negative
|
||||
// lookup we have to bailout as this key might be equal to the
|
||||
// key we are looking for.
|
||||
|
||||
// Check if the entry name is not an internalized string.
|
||||
// Check if the entry name is not a unique name.
|
||||
Label cont;
|
||||
__ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
|
||||
__ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset),
|
||||
kIsInternalizedMask);
|
||||
__ j(zero, &maybe_in_dictionary);
|
||||
__ j(not_zero, &cont);
|
||||
__ cmpb(FieldOperand(scratch, Map::kInstanceTypeOffset),
|
||||
static_cast<int8_t>(SYMBOL_TYPE));
|
||||
__ j(not_equal, &maybe_in_dictionary);
|
||||
__ bind(&cont);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,14 +320,14 @@ class NumberToStringStub: public PlatformCodeStub {
|
||||
};
|
||||
|
||||
|
||||
class StringDictionaryLookupStub: public PlatformCodeStub {
|
||||
class NameDictionaryLookupStub: public PlatformCodeStub {
|
||||
public:
|
||||
enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
|
||||
|
||||
StringDictionaryLookupStub(Register dictionary,
|
||||
Register result,
|
||||
Register index,
|
||||
LookupMode mode)
|
||||
NameDictionaryLookupStub(Register dictionary,
|
||||
Register result,
|
||||
Register index,
|
||||
LookupMode mode)
|
||||
: dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
|
||||
|
||||
void Generate(MacroAssembler* masm);
|
||||
@ -336,7 +336,7 @@ class StringDictionaryLookupStub: public PlatformCodeStub {
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register properties,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register r0);
|
||||
|
||||
static void GeneratePositiveLookup(MacroAssembler* masm,
|
||||
@ -354,14 +354,14 @@ class StringDictionaryLookupStub: public PlatformCodeStub {
|
||||
static const int kTotalProbes = 20;
|
||||
|
||||
static const int kCapacityOffset =
|
||||
StringDictionary::kHeaderSize +
|
||||
StringDictionary::kCapacityIndex * kPointerSize;
|
||||
NameDictionary::kHeaderSize +
|
||||
NameDictionary::kCapacityIndex * kPointerSize;
|
||||
|
||||
static const int kElementsStartOffset =
|
||||
StringDictionary::kHeaderSize +
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
NameDictionary::kHeaderSize +
|
||||
NameDictionary::kElementsStartIndex * kPointerSize;
|
||||
|
||||
Major MajorKey() { return StringDictionaryLookup; }
|
||||
Major MajorKey() { return NameDictionaryLookup; }
|
||||
|
||||
int MinorKey() {
|
||||
return DictionaryBits::encode(dictionary_.code()) |
|
||||
|
@ -60,11 +60,11 @@ static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
|
||||
|
||||
// Generated code falls through if the receiver is a regular non-global
|
||||
// JS object with slow properties and no interceptors.
|
||||
static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register r0,
|
||||
Register r1,
|
||||
Label* miss) {
|
||||
static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register r0,
|
||||
Register r1,
|
||||
Label* miss) {
|
||||
// Register usage:
|
||||
// receiver: holds the receiver on entry and is unchanged.
|
||||
// r0: used to hold receiver instance type.
|
||||
@ -127,21 +127,21 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
|
||||
Label done;
|
||||
|
||||
// Probe the dictionary.
|
||||
StringDictionaryLookupStub::GeneratePositiveLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
elements,
|
||||
name,
|
||||
r0,
|
||||
r1);
|
||||
NameDictionaryLookupStub::GeneratePositiveLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
elements,
|
||||
name,
|
||||
r0,
|
||||
r1);
|
||||
|
||||
// If probing finds an entry in the dictionary, r0 contains the
|
||||
// index into the dictionary. Check that the value is a normal
|
||||
// property.
|
||||
__ bind(&done);
|
||||
const int kElementsStartOffset =
|
||||
StringDictionary::kHeaderSize +
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
NameDictionary::kHeaderSize +
|
||||
NameDictionary::kElementsStartIndex * kPointerSize;
|
||||
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
|
||||
__ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
|
||||
Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
|
||||
@ -182,21 +182,21 @@ static void GenerateDictionaryStore(MacroAssembler* masm,
|
||||
|
||||
|
||||
// Probe the dictionary.
|
||||
StringDictionaryLookupStub::GeneratePositiveLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
elements,
|
||||
name,
|
||||
r0,
|
||||
r1);
|
||||
NameDictionaryLookupStub::GeneratePositiveLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
elements,
|
||||
name,
|
||||
r0,
|
||||
r1);
|
||||
|
||||
// If probing finds an entry in the dictionary, r0 contains the
|
||||
// index into the dictionary. Check that the value is a normal
|
||||
// property that is not read only.
|
||||
__ bind(&done);
|
||||
const int kElementsStartOffset =
|
||||
StringDictionary::kHeaderSize +
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
NameDictionary::kHeaderSize +
|
||||
NameDictionary::kElementsStartIndex * kPointerSize;
|
||||
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
|
||||
const int kTypeAndReadOnlyMask =
|
||||
(PropertyDetails::TypeField::kMask |
|
||||
@ -292,31 +292,36 @@ static void GenerateFastArrayLoad(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Checks whether a key is an array index string or an internalized string.
|
||||
// Falls through if the key is an internalized string.
|
||||
static void GenerateKeyStringCheck(MacroAssembler* masm,
|
||||
Register key,
|
||||
Register map,
|
||||
Register hash,
|
||||
Label* index_string,
|
||||
Label* not_internalized) {
|
||||
// Checks whether a key is an array index string or a unique name.
|
||||
// Falls through if the key is a unique name.
|
||||
static void GenerateKeyNameCheck(MacroAssembler* masm,
|
||||
Register key,
|
||||
Register map,
|
||||
Register hash,
|
||||
Label* index_string,
|
||||
Label* not_unique) {
|
||||
// Register use:
|
||||
// key - holds the key and is unchanged. Assumed to be non-smi.
|
||||
// Scratch registers:
|
||||
// map - used to hold the map of the key.
|
||||
// hash - used to hold the hash of the key.
|
||||
__ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
|
||||
__ j(above_equal, not_internalized);
|
||||
Label unique;
|
||||
__ CmpObjectType(key, LAST_UNIQUE_NAME_TYPE, map);
|
||||
__ j(above, not_unique);
|
||||
STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
|
||||
__ j(equal, &unique);
|
||||
|
||||
// Is the string an array index, with cached numeric value?
|
||||
__ mov(hash, FieldOperand(key, String::kHashFieldOffset));
|
||||
__ test(hash, Immediate(String::kContainsCachedArrayIndexMask));
|
||||
__ mov(hash, FieldOperand(key, Name::kHashFieldOffset));
|
||||
__ test(hash, Immediate(Name::kContainsCachedArrayIndexMask));
|
||||
__ j(zero, index_string);
|
||||
|
||||
// Is the string internalized?
|
||||
STATIC_ASSERT(kInternalizedTag != 0);
|
||||
__ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsInternalizedMask);
|
||||
__ j(zero, not_internalized);
|
||||
__ j(zero, not_unique);
|
||||
|
||||
__ bind(&unique);
|
||||
}
|
||||
|
||||
|
||||
@ -403,11 +408,11 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
// -- edx : receiver
|
||||
// -- esp[0] : return address
|
||||
// -----------------------------------
|
||||
Label slow, check_string, index_smi, index_string, property_array_property;
|
||||
Label slow, check_name, index_smi, index_name, property_array_property;
|
||||
Label probe_dictionary, check_number_dictionary;
|
||||
|
||||
// Check that the key is a smi.
|
||||
__ JumpIfNotSmi(ecx, &check_string);
|
||||
__ JumpIfNotSmi(ecx, &check_name);
|
||||
__ bind(&index_smi);
|
||||
// Now the key is known to be a smi. This place is also jumped to from
|
||||
// where a numeric string is converted to a smi.
|
||||
@ -458,8 +463,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ IncrementCounter(counters->keyed_load_generic_slow(), 1);
|
||||
GenerateRuntimeGetProperty(masm);
|
||||
|
||||
__ bind(&check_string);
|
||||
GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow);
|
||||
__ bind(&check_name);
|
||||
GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow);
|
||||
|
||||
GenerateKeyedLoadReceiverCheck(
|
||||
masm, edx, eax, Map::kHasNamedInterceptor, &slow);
|
||||
@ -568,7 +573,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
|
||||
__ ret(0);
|
||||
|
||||
__ bind(&index_string);
|
||||
__ bind(&index_name);
|
||||
__ IndexFromHash(ebx, ecx);
|
||||
// Now jump to the place where smi keys are handled.
|
||||
__ jmp(&index_smi);
|
||||
@ -1016,7 +1021,7 @@ void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
|
||||
// Get the receiver of the function from the stack; 1 ~ return address.
|
||||
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
|
||||
|
||||
GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
|
||||
GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
|
||||
|
||||
// eax: elements
|
||||
// Search the dictionary placing the result in edi.
|
||||
@ -1132,11 +1137,11 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
|
||||
|
||||
Label do_call, slow_call, slow_load, slow_reload_receiver;
|
||||
Label check_number_dictionary, check_string, lookup_monomorphic_cache;
|
||||
Label index_smi, index_string;
|
||||
Label check_number_dictionary, check_name, lookup_monomorphic_cache;
|
||||
Label index_smi, index_name;
|
||||
|
||||
// Check that the key is a smi.
|
||||
__ JumpIfNotSmi(ecx, &check_string);
|
||||
__ JumpIfNotSmi(ecx, &check_name);
|
||||
|
||||
__ bind(&index_smi);
|
||||
// Now the key is known to be a smi. This place is also jumped to from
|
||||
@ -1195,10 +1200,10 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
__ mov(edi, eax);
|
||||
__ jmp(&do_call);
|
||||
|
||||
__ bind(&check_string);
|
||||
GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call);
|
||||
__ bind(&check_name);
|
||||
GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow_call);
|
||||
|
||||
// The key is known to be an internalized string.
|
||||
// The key is known to be a unique name.
|
||||
// If the receiver is a regular JS object with slow properties then do
|
||||
// a quick inline probe of the receiver's dictionary.
|
||||
// Otherwise do the monomorphic cache probe.
|
||||
@ -1224,14 +1229,14 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
__ bind(&slow_call);
|
||||
// This branch is taken if:
|
||||
// - the receiver requires boxing or access check,
|
||||
// - the key is neither smi nor an internalized string,
|
||||
// - the key is neither smi nor a unique name,
|
||||
// - the value loaded is not a function,
|
||||
// - there is hope that the runtime will create a monomorphic call stub
|
||||
// that will get fetched next time.
|
||||
__ IncrementCounter(counters->keyed_call_generic_slow(), 1);
|
||||
GenerateMiss(masm, argc);
|
||||
|
||||
__ bind(&index_string);
|
||||
__ bind(&index_name);
|
||||
__ IndexFromHash(ebx, ecx);
|
||||
// Now jump to the place where smi keys are handled.
|
||||
__ jmp(&index_smi);
|
||||
@ -1276,10 +1281,10 @@ void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
|
||||
// -- esp[(argc + 1) * 4] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
// Check if the name is a string.
|
||||
// Check if the name is really a name.
|
||||
Label miss;
|
||||
__ JumpIfSmi(ecx, &miss);
|
||||
Condition cond = masm->IsObjectStringType(ecx, eax, eax);
|
||||
Condition cond = masm->IsObjectNameType(ecx, eax, eax);
|
||||
__ j(NegateCondition(cond), &miss);
|
||||
CallICBase::GenerateNormal(masm, argc);
|
||||
__ bind(&miss);
|
||||
@ -1313,7 +1318,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
||||
// -----------------------------------
|
||||
Label miss;
|
||||
|
||||
GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
|
||||
GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
|
||||
|
||||
// eax: elements
|
||||
// Search the dictionary placing the result in eax.
|
||||
@ -1437,7 +1442,7 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
|
||||
|
||||
Label miss, restore_miss;
|
||||
|
||||
GenerateStringDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
|
||||
GenerateNameDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
|
||||
|
||||
// A lot of registers are needed for storing to slow case
|
||||
// objects. Push and restore receiver but rely on
|
||||
|
@ -643,6 +643,16 @@ Condition MacroAssembler::IsObjectStringType(Register heap_object,
|
||||
}
|
||||
|
||||
|
||||
Condition MacroAssembler::IsObjectNameType(Register heap_object,
|
||||
Register map,
|
||||
Register instance_type) {
|
||||
mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
|
||||
movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
|
||||
cmpb(instance_type, static_cast<int8_t>(LAST_NAME_TYPE));
|
||||
return below_equal;
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::IsObjectJSObjectType(Register heap_object,
|
||||
Register map,
|
||||
Register scratch,
|
||||
@ -710,6 +720,19 @@ void MacroAssembler::AssertString(Register object) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::AssertName(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
test(object, Immediate(kSmiTagMask));
|
||||
Check(not_equal, "Operand is a smi and not a name");
|
||||
push(object);
|
||||
mov(object, FieldOperand(object, HeapObject::kMapOffset));
|
||||
CmpInstanceType(object, LAST_NAME_TYPE);
|
||||
pop(object);
|
||||
Check(below_equal, "Operand is not a name");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::AssertNotSmi(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
test(object, Immediate(kSmiTagMask));
|
||||
|
@ -423,6 +423,15 @@ class MacroAssembler: public Assembler {
|
||||
Register map,
|
||||
Register instance_type);
|
||||
|
||||
// Check if the object in register heap_object is a name. Afterwards the
|
||||
// register map contains the object map and the register instance_type
|
||||
// contains the instance_type. The registers map and instance_type can be the
|
||||
// same in which case it contains the instance type afterwards. Either of the
|
||||
// registers map and instance_type can be the same as heap_object.
|
||||
Condition IsObjectNameType(Register heap_object,
|
||||
Register map,
|
||||
Register instance_type);
|
||||
|
||||
// Check if a heap object's type is in the JSObject range, not including
|
||||
// JSFunction. The object's map will be loaded in the map register.
|
||||
// Any or all of the three registers may be the same.
|
||||
@ -513,6 +522,9 @@ class MacroAssembler: public Assembler {
|
||||
// Abort execution if argument is not a string, enabled via --debug-code.
|
||||
void AssertString(Register object);
|
||||
|
||||
// Abort execution if argument is not a name, enabled via --debug-code.
|
||||
void AssertName(Register object);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Exception handling
|
||||
|
||||
|
@ -141,14 +141,14 @@ static void ProbeTable(Isolate* isolate,
|
||||
// the property. This function may return false negatives, so miss_label
|
||||
// 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 an internalized string and receiver must be a heap object.
|
||||
// Name must be unique and receiver must be a heap object.
|
||||
static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
|
||||
Label* miss_label,
|
||||
Register receiver,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register r0,
|
||||
Register r1) {
|
||||
ASSERT(name->IsInternalizedString());
|
||||
ASSERT(name->IsUniqueName());
|
||||
Counters* counters = masm->isolate()->counters();
|
||||
__ IncrementCounter(counters->negative_lookups(), 1);
|
||||
__ IncrementCounter(counters->negative_lookups_miss(), 1);
|
||||
@ -177,12 +177,12 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
|
||||
__ j(not_equal, miss_label);
|
||||
|
||||
Label done;
|
||||
StringDictionaryLookupStub::GenerateNegativeLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
properties,
|
||||
name,
|
||||
r1);
|
||||
NameDictionaryLookupStub::GenerateNegativeLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
properties,
|
||||
name,
|
||||
r1);
|
||||
__ bind(&done);
|
||||
__ DecrementCounter(counters->negative_lookups_miss(), 1);
|
||||
}
|
||||
@ -227,7 +227,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
__ JumpIfSmi(receiver, &miss);
|
||||
|
||||
// Get the map of the receiver and compute the hash.
|
||||
__ mov(offset, FieldOperand(name, String::kHashFieldOffset));
|
||||
__ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
|
||||
__ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
__ xor_(offset, flags);
|
||||
// We mask out the last two bits because they are not part of the hash and
|
||||
@ -241,7 +241,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra);
|
||||
|
||||
// Primary miss: Compute hash for secondary probe.
|
||||
__ mov(offset, FieldOperand(name, String::kHashFieldOffset));
|
||||
__ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
|
||||
__ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
__ xor_(offset, flags);
|
||||
__ and_(offset, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
|
||||
@ -547,7 +547,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
void Compile(MacroAssembler* masm,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
LookupResult* lookup,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
@ -579,7 +579,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
Register scratch3,
|
||||
Handle<JSObject> interceptor_holder,
|
||||
LookupResult* lookup,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
const CallOptimization& optimization,
|
||||
Label* miss_label) {
|
||||
ASSERT(optimization.is_constant_call());
|
||||
@ -672,7 +672,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Register scratch3,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> interceptor_holder,
|
||||
Label* miss_label) {
|
||||
Register holder =
|
||||
@ -760,7 +760,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
|
||||
Handle<JSObject> object,
|
||||
int index,
|
||||
Handle<Map> transition,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register receiver_reg,
|
||||
Register name_reg,
|
||||
Register scratch1,
|
||||
@ -894,7 +894,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
|
||||
// property.
|
||||
static void GenerateCheckPropertyCell(MacroAssembler* masm,
|
||||
Handle<GlobalObject> global,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register scratch,
|
||||
Label* miss) {
|
||||
Handle<JSGlobalPropertyCell> cell =
|
||||
@ -917,7 +917,7 @@ static void GenerateCheckPropertyCell(MacroAssembler* masm,
|
||||
static void GenerateCheckPropertyCells(MacroAssembler* masm,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register scratch,
|
||||
Label* miss) {
|
||||
Handle<JSObject> current = object;
|
||||
@ -948,7 +948,7 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
|
||||
Register holder_reg,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
int save_at_depth,
|
||||
Label* miss,
|
||||
PrototypeCheckType check) {
|
||||
@ -980,11 +980,12 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
|
||||
if (!current->HasFastProperties() &&
|
||||
!current->IsJSGlobalObject() &&
|
||||
!current->IsJSGlobalProxy()) {
|
||||
if (!name->IsInternalizedString()) {
|
||||
name = factory()->InternalizeString(name);
|
||||
if (!name->IsUniqueName()) {
|
||||
ASSERT(name->IsString());
|
||||
name = factory()->InternalizeString(Handle<String>::cast(name));
|
||||
}
|
||||
ASSERT(current->property_dictionary()->FindEntry(*name) ==
|
||||
StringDictionary::kNotFound);
|
||||
NameDictionary::kNotFound);
|
||||
|
||||
GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
|
||||
scratch1, scratch2);
|
||||
@ -1070,7 +1071,7 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend(
|
||||
Handle<JSObject> object,
|
||||
Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* success,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
Label miss;
|
||||
@ -1091,13 +1092,13 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend(
|
||||
|
||||
// Probe the dictionary.
|
||||
Label probe_done, pop_and_miss;
|
||||
StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
|
||||
&pop_and_miss,
|
||||
&probe_done,
|
||||
dictionary,
|
||||
this->name(),
|
||||
scratch2(),
|
||||
scratch3());
|
||||
NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
|
||||
&pop_and_miss,
|
||||
&probe_done,
|
||||
dictionary,
|
||||
this->name(),
|
||||
scratch2(),
|
||||
scratch3());
|
||||
__ bind(&pop_and_miss);
|
||||
if (must_preserve_dictionary_reg) {
|
||||
__ pop(dictionary);
|
||||
@ -1109,8 +1110,8 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend(
|
||||
// index into the dictionary. Check that the value is the callback.
|
||||
Register index = scratch2();
|
||||
const int kElementsStartOffset =
|
||||
StringDictionary::kHeaderSize +
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
NameDictionary::kHeaderSize +
|
||||
NameDictionary::kElementsStartIndex * kPointerSize;
|
||||
const int kValueOffset = kElementsStartOffset + kPointerSize;
|
||||
__ mov(scratch3(),
|
||||
Operand(dictionary, index, times_4, kValueOffset - kHeapObjectTag));
|
||||
@ -1129,7 +1130,7 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend(
|
||||
void BaseLoadStubCompiler::NonexistentHandlerFrontend(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> last,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* success,
|
||||
Handle<GlobalObject> global) {
|
||||
Label miss;
|
||||
@ -1222,7 +1223,7 @@ void BaseLoadStubCompiler::GenerateLoadInterceptor(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> interceptor_holder,
|
||||
LookupResult* lookup,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
ASSERT(interceptor_holder->HasNamedInterceptor());
|
||||
ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
|
||||
|
||||
@ -1318,7 +1319,7 @@ void BaseLoadStubCompiler::GenerateLoadInterceptor(
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
|
||||
void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
|
||||
if (kind_ == Code::KEYED_CALL_IC) {
|
||||
__ cmp(ecx, Immediate(name));
|
||||
__ j(not_equal, miss);
|
||||
@ -1328,7 +1329,7 @@ void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
|
||||
|
||||
void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* miss) {
|
||||
ASSERT(holder->IsGlobalObject());
|
||||
|
||||
@ -1390,7 +1391,7 @@ void CallStubCompiler::GenerateMissBranch() {
|
||||
Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
PropertyIndex index,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- ecx : name
|
||||
// -- esp[0] : return address
|
||||
@ -2324,7 +2325,7 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
|
||||
|
||||
void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
CheckType check,
|
||||
Label* success) {
|
||||
// ----------- S t a t e -------------
|
||||
@ -2436,14 +2437,14 @@ void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
|
||||
Handle<Code> CallStubCompiler::CompileCallConstant(
|
||||
Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
CheckType check,
|
||||
Handle<JSFunction> function) {
|
||||
|
||||
if (HasCustomCallGenerator(function)) {
|
||||
Handle<Code> code = CompileCustomCall(object, holder,
|
||||
Handle<JSGlobalPropertyCell>::null(),
|
||||
function, name);
|
||||
function, Handle<String>::cast(name));
|
||||
// A null handle means bail out to the regular compiler code below.
|
||||
if (!code.is_null()) return code;
|
||||
}
|
||||
@ -2461,7 +2462,7 @@ Handle<Code> CallStubCompiler::CompileCallConstant(
|
||||
|
||||
Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- ecx : name
|
||||
// -- esp[0] : return address
|
||||
@ -2523,7 +2524,7 @@ Handle<Code> CallStubCompiler::CompileCallGlobal(
|
||||
Handle<GlobalObject> holder,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
Handle<JSFunction> function,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- ecx : name
|
||||
// -- esp[0] : return address
|
||||
@ -2533,7 +2534,8 @@ Handle<Code> CallStubCompiler::CompileCallGlobal(
|
||||
// -----------------------------------
|
||||
|
||||
if (HasCustomCallGenerator(function)) {
|
||||
Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
|
||||
Handle<Code> code = CompileCustomCall(
|
||||
object, holder, cell, function, Handle<String>::cast(name));
|
||||
// A null handle means bail out to the regular compiler code below.
|
||||
if (!code.is_null()) return code;
|
||||
}
|
||||
@ -2582,7 +2584,7 @@ Handle<Code> CallStubCompiler::CompileCallGlobal(
|
||||
Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
|
||||
int index,
|
||||
Handle<Map> transition,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : value
|
||||
// -- ecx : name
|
||||
@ -2613,7 +2615,7 @@ Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
|
||||
|
||||
|
||||
Handle<Code> StoreStubCompiler::CompileStoreCallback(
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
@ -2703,7 +2705,7 @@ void StoreStubCompiler::GenerateStoreViaSetter(
|
||||
|
||||
|
||||
Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> setter) {
|
||||
@ -2735,7 +2737,7 @@ Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
|
||||
|
||||
Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
|
||||
Handle<JSObject> receiver,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : value
|
||||
// -- ecx : name
|
||||
@ -2782,7 +2784,7 @@ Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
|
||||
Handle<Code> StoreStubCompiler::CompileStoreGlobal(
|
||||
Handle<GlobalObject> object,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : value
|
||||
// -- ecx : name
|
||||
@ -2830,7 +2832,7 @@ Handle<Code> StoreStubCompiler::CompileStoreGlobal(
|
||||
Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
|
||||
int index,
|
||||
Handle<Map> transition,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : value
|
||||
// -- ecx : key
|
||||
@ -2931,7 +2933,7 @@ Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
|
||||
Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> last,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<GlobalObject> global) {
|
||||
Label success;
|
||||
|
||||
@ -2962,7 +2964,7 @@ Register* KeyedLoadStubCompiler::registers() {
|
||||
}
|
||||
|
||||
|
||||
void KeyedLoadStubCompiler::GenerateNameCheck(Handle<String> name,
|
||||
void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
|
||||
Register name_reg,
|
||||
Label* miss) {
|
||||
__ cmp(name_reg, Immediate(name));
|
||||
@ -3011,7 +3013,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
|
||||
Handle<JSObject> object,
|
||||
Handle<GlobalObject> global,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
bool is_dont_delete) {
|
||||
Label success, miss;
|
||||
|
||||
@ -3079,7 +3081,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
|
||||
Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
|
||||
MapHandleList* receiver_maps,
|
||||
CodeHandleList* handlers,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Code::StubType type,
|
||||
IcCheckType check) {
|
||||
Label miss;
|
||||
|
@ -577,7 +577,10 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
|
||||
object->elements()->length() == 0) {
|
||||
Handle<Map> map(object->map());
|
||||
for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
|
||||
Handle<String> key(map->instance_descriptors()->GetKey(i), isolate_);
|
||||
Handle<Name> name(map->instance_descriptors()->GetKey(i), isolate_);
|
||||
// TODO(rossberg): Should this throw?
|
||||
if (!name->IsString()) continue;
|
||||
Handle<String> key = Handle<String>::cast(name);
|
||||
PropertyDetails details = map->instance_descriptors()->GetDetails(i);
|
||||
if (details.IsDontEnum() || details.IsDeleted()) continue;
|
||||
Handle<Object> property;
|
||||
|
136
src/log.cc
136
src/log.cc
@ -427,6 +427,14 @@ class Logger::NameBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
void AppendHex(uint32_t n) {
|
||||
Vector<char> buffer(utf8_buffer_ + utf8_pos_, kUtf8BufferSize - utf8_pos_);
|
||||
int size = OS::SNPrintF(buffer, "%x", n);
|
||||
if (size > 0 && utf8_pos_ + size <= kUtf8BufferSize) {
|
||||
utf8_pos_ += size;
|
||||
}
|
||||
}
|
||||
|
||||
const char* get() { return utf8_buffer_; }
|
||||
int size() const { return utf8_pos_; }
|
||||
|
||||
@ -635,6 +643,8 @@ void Logger::ApiNamedSecurityCheck(Object* key) {
|
||||
SmartArrayPointer<char> str =
|
||||
String::cast(key)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
ApiEvent("api,check-security,\"%s\"\n", *str);
|
||||
} else if (key->IsSymbol()) {
|
||||
ApiEvent("api,check-security,symbol(hash %x)\n", Symbol::cast(key)->Hash());
|
||||
} else if (key->IsUndefined()) {
|
||||
ApiEvent("api,check-security,undefined\n");
|
||||
} else {
|
||||
@ -813,14 +823,19 @@ void Logger::ApiIndexedSecurityCheck(uint32_t index) {
|
||||
void Logger::ApiNamedPropertyAccess(const char* tag,
|
||||
JSObject* holder,
|
||||
Object* name) {
|
||||
ASSERT(name->IsString());
|
||||
ASSERT(name->IsName());
|
||||
if (!log_->IsEnabled() || !FLAG_log_api) return;
|
||||
String* class_name_obj = holder->class_name();
|
||||
SmartArrayPointer<char> class_name =
|
||||
class_name_obj->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
SmartArrayPointer<char> property_name =
|
||||
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
|
||||
if (name->IsString()) {
|
||||
SmartArrayPointer<char> property_name =
|
||||
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
ApiEvent("api,%s,\"%s\",\"%s\"\n", tag, *class_name, *property_name);
|
||||
} else {
|
||||
uint32_t hash = Symbol::cast(name)->Hash();
|
||||
ApiEvent("api,%s,\"%s\",symbol(hash %x)\n", tag, *class_name, hash);
|
||||
}
|
||||
}
|
||||
|
||||
void Logger::ApiIndexedPropertyAccess(const char* tag,
|
||||
@ -874,7 +889,7 @@ void Logger::DeleteEventStatic(const char* name, void* object) {
|
||||
LOGGER->DeleteEvent(name, object);
|
||||
}
|
||||
|
||||
void Logger::CallbackEventInternal(const char* prefix, const char* name,
|
||||
void Logger::CallbackEventInternal(const char* prefix, Name* name,
|
||||
Address entry_point) {
|
||||
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
||||
LogMessageBuilder msg(this);
|
||||
@ -882,33 +897,33 @@ void Logger::CallbackEventInternal(const char* prefix, const char* name,
|
||||
kLogEventsNames[CODE_CREATION_EVENT],
|
||||
kLogEventsNames[CALLBACK_TAG]);
|
||||
msg.AppendAddress(entry_point);
|
||||
msg.Append(",1,\"%s%s\"", prefix, name);
|
||||
if (name->IsString()) {
|
||||
SmartArrayPointer<char> str =
|
||||
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
msg.Append(",1,\"%s%s\"", prefix, *str);
|
||||
} else {
|
||||
msg.Append(",1,symbol(hash %x)", prefix, Name::cast(name)->Hash());
|
||||
}
|
||||
msg.Append('\n');
|
||||
msg.WriteToLogFile();
|
||||
}
|
||||
|
||||
|
||||
void Logger::CallbackEvent(String* name, Address entry_point) {
|
||||
void Logger::CallbackEvent(Name* name, Address entry_point) {
|
||||
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
||||
SmartArrayPointer<char> str =
|
||||
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
CallbackEventInternal("", *str, entry_point);
|
||||
CallbackEventInternal("", name, entry_point);
|
||||
}
|
||||
|
||||
|
||||
void Logger::GetterCallbackEvent(String* name, Address entry_point) {
|
||||
void Logger::GetterCallbackEvent(Name* name, Address entry_point) {
|
||||
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
||||
SmartArrayPointer<char> str =
|
||||
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
CallbackEventInternal("get ", *str, entry_point);
|
||||
CallbackEventInternal("get ", name, entry_point);
|
||||
}
|
||||
|
||||
|
||||
void Logger::SetterCallbackEvent(String* name, Address entry_point) {
|
||||
void Logger::SetterCallbackEvent(Name* name, Address entry_point) {
|
||||
if (!log_->IsEnabled() || !FLAG_log_code) return;
|
||||
SmartArrayPointer<char> str =
|
||||
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
CallbackEventInternal("set ", *str, entry_point);
|
||||
CallbackEventInternal("set ", name, entry_point);
|
||||
}
|
||||
|
||||
|
||||
@ -954,13 +969,19 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
|
||||
void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
Code* code,
|
||||
String* name) {
|
||||
Name* name) {
|
||||
if (!is_logging_code_events()) return;
|
||||
if (FLAG_ll_prof || Serializer::enabled() || code_event_handler_ != NULL) {
|
||||
name_buffer_->Reset();
|
||||
name_buffer_->AppendBytes(kLogEventsNames[tag]);
|
||||
name_buffer_->AppendByte(':');
|
||||
name_buffer_->AppendString(name);
|
||||
if (name->IsString()) {
|
||||
name_buffer_->AppendString(String::cast(name));
|
||||
} else {
|
||||
name_buffer_->AppendBytes("symbol(hash ");
|
||||
name_buffer_->AppendHex(Name::cast(name)->Hash());
|
||||
name_buffer_->AppendByte(')');
|
||||
}
|
||||
}
|
||||
if (code_event_handler_ != NULL) {
|
||||
IssueCodeAddedEvent(code, NULL, name_buffer_->get(), name_buffer_->size());
|
||||
@ -979,9 +1000,14 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
kLogEventsNames[tag],
|
||||
code->kind());
|
||||
msg.AppendAddress(code->address());
|
||||
msg.Append(",%d,\"", code->ExecutableSize());
|
||||
msg.AppendDetailed(name, false);
|
||||
msg.Append('"');
|
||||
msg.Append(",%d,", code->ExecutableSize());
|
||||
if (name->IsString()) {
|
||||
msg.Append('"');
|
||||
msg.AppendDetailed(String::cast(name), false);
|
||||
msg.Append('"');
|
||||
} else {
|
||||
msg.Append("symbol(hash %x)", Name::cast(name)->Hash());
|
||||
}
|
||||
msg.Append('\n');
|
||||
msg.WriteToLogFile();
|
||||
}
|
||||
@ -1000,14 +1026,20 @@ static const char* ComputeMarker(Code* code) {
|
||||
void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
Code* code,
|
||||
SharedFunctionInfo* shared,
|
||||
String* name) {
|
||||
Name* name) {
|
||||
if (!is_logging_code_events()) return;
|
||||
if (FLAG_ll_prof || Serializer::enabled() || code_event_handler_ != NULL) {
|
||||
name_buffer_->Reset();
|
||||
name_buffer_->AppendBytes(kLogEventsNames[tag]);
|
||||
name_buffer_->AppendByte(':');
|
||||
name_buffer_->AppendBytes(ComputeMarker(code));
|
||||
name_buffer_->AppendString(name);
|
||||
if (name->IsString()) {
|
||||
name_buffer_->AppendString(String::cast(name));
|
||||
} else {
|
||||
name_buffer_->AppendBytes("symbol(hash ");
|
||||
name_buffer_->AppendHex(Name::cast(name)->Hash());
|
||||
name_buffer_->AppendByte(')');
|
||||
}
|
||||
}
|
||||
if (code_event_handler_ != NULL) {
|
||||
Script* script =
|
||||
@ -1030,14 +1062,20 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
return;
|
||||
|
||||
LogMessageBuilder msg(this);
|
||||
SmartArrayPointer<char> str =
|
||||
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
msg.Append("%s,%s,%d,",
|
||||
kLogEventsNames[CODE_CREATION_EVENT],
|
||||
kLogEventsNames[tag],
|
||||
code->kind());
|
||||
msg.AppendAddress(code->address());
|
||||
msg.Append(",%d,\"%s\",", code->ExecutableSize(), *str);
|
||||
msg.Append(",%d,", code->ExecutableSize());
|
||||
if (name->IsString()) {
|
||||
SmartArrayPointer<char> str =
|
||||
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
msg.Append("\"%s\"", *str);
|
||||
} else {
|
||||
msg.Append("symbol(hash %x)", Name::cast(name)->Hash());
|
||||
}
|
||||
msg.Append(',');
|
||||
msg.AppendAddress(shared->address());
|
||||
msg.Append(",%s", ComputeMarker(code));
|
||||
msg.Append('\n');
|
||||
@ -1051,7 +1089,7 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
Code* code,
|
||||
SharedFunctionInfo* shared,
|
||||
String* source, int line) {
|
||||
Name* source, int line) {
|
||||
if (!is_logging_code_events()) return;
|
||||
if (FLAG_ll_prof || Serializer::enabled() || code_event_handler_ != NULL) {
|
||||
name_buffer_->Reset();
|
||||
@ -1060,7 +1098,13 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
name_buffer_->AppendBytes(ComputeMarker(code));
|
||||
name_buffer_->AppendString(shared->DebugName());
|
||||
name_buffer_->AppendByte(' ');
|
||||
name_buffer_->AppendString(source);
|
||||
if (source->IsString()) {
|
||||
name_buffer_->AppendString(String::cast(source));
|
||||
} else {
|
||||
name_buffer_->AppendBytes("symbol(hash ");
|
||||
name_buffer_->AppendHex(Name::cast(source)->Hash());
|
||||
name_buffer_->AppendByte(')');
|
||||
}
|
||||
name_buffer_->AppendByte(':');
|
||||
name_buffer_->AppendInt(line);
|
||||
}
|
||||
@ -1083,18 +1127,20 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
|
||||
LogMessageBuilder msg(this);
|
||||
SmartArrayPointer<char> name =
|
||||
shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
SmartArrayPointer<char> sourcestr =
|
||||
source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
msg.Append("%s,%s,%d,",
|
||||
kLogEventsNames[CODE_CREATION_EVENT],
|
||||
kLogEventsNames[tag],
|
||||
code->kind());
|
||||
msg.AppendAddress(code->address());
|
||||
msg.Append(",%d,\"%s %s:%d\",",
|
||||
code->ExecutableSize(),
|
||||
*name,
|
||||
*sourcestr,
|
||||
line);
|
||||
msg.Append(",%d,\"%s ", code->ExecutableSize(), *name);
|
||||
if (source->IsString()) {
|
||||
SmartArrayPointer<char> sourcestr =
|
||||
String::cast(source)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
|
||||
msg.Append("%s", *sourcestr);
|
||||
} else {
|
||||
msg.Append("symbol(hash %x)", Name::cast(source)->Hash());
|
||||
}
|
||||
msg.Append(":%d\",", line);
|
||||
msg.AppendAddress(shared->address());
|
||||
msg.Append(",%s", ComputeMarker(code));
|
||||
msg.Append('\n');
|
||||
@ -1298,7 +1344,7 @@ void Logger::ResourceEvent(const char* name, const char* tag) {
|
||||
}
|
||||
|
||||
|
||||
void Logger::SuspectReadEvent(String* name, Object* obj) {
|
||||
void Logger::SuspectReadEvent(Name* name, Object* obj) {
|
||||
if (!log_->IsEnabled() || !FLAG_log_suspect) return;
|
||||
LogMessageBuilder msg(this);
|
||||
String* class_name = obj->IsJSObject()
|
||||
@ -1307,9 +1353,13 @@ void Logger::SuspectReadEvent(String* name, Object* obj) {
|
||||
msg.Append("suspect-read,");
|
||||
msg.Append(class_name);
|
||||
msg.Append(',');
|
||||
msg.Append('"');
|
||||
msg.Append(name);
|
||||
msg.Append('"');
|
||||
if (name->IsString()) {
|
||||
msg.Append('"');
|
||||
msg.Append(String::cast(name));
|
||||
msg.Append('"');
|
||||
} else {
|
||||
msg.Append("symbol(hash %x)", Name::cast(name)->Hash());
|
||||
}
|
||||
msg.Append('\n');
|
||||
msg.WriteToLogFile();
|
||||
}
|
||||
@ -1735,9 +1785,9 @@ void Logger::LogAccessorCallbacks() {
|
||||
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
|
||||
if (!obj->IsExecutableAccessorInfo()) continue;
|
||||
ExecutableAccessorInfo* ai = ExecutableAccessorInfo::cast(obj);
|
||||
if (!ai->name()->IsString()) continue;
|
||||
String* name = String::cast(ai->name());
|
||||
if (!ai->name()->IsName()) continue;
|
||||
Address getter_entry = v8::ToCData<Address>(ai->getter());
|
||||
Name* name = Name::cast(ai->name());
|
||||
if (getter_entry != 0) {
|
||||
PROFILE(ISOLATE, GetterCallbackEvent(name, getter_entry));
|
||||
}
|
||||
|
16
src/log.h
16
src/log.h
@ -203,7 +203,7 @@ class Logger {
|
||||
|
||||
// Emits an event that an undefined property was read from an
|
||||
// object.
|
||||
void SuspectReadEvent(String* name, Object* obj);
|
||||
void SuspectReadEvent(Name* name, Object* obj);
|
||||
|
||||
// Emits an event when a message is put on or read from a debugging queue.
|
||||
// DebugTag lets us put a call-site specific label on the event.
|
||||
@ -224,22 +224,22 @@ class Logger {
|
||||
|
||||
// ==== Events logged by --log-code. ====
|
||||
// Emits a code event for a callback function.
|
||||
void CallbackEvent(String* name, Address entry_point);
|
||||
void GetterCallbackEvent(String* name, Address entry_point);
|
||||
void SetterCallbackEvent(String* name, Address entry_point);
|
||||
void CallbackEvent(Name* name, Address entry_point);
|
||||
void GetterCallbackEvent(Name* name, Address entry_point);
|
||||
void SetterCallbackEvent(Name* name, Address entry_point);
|
||||
// Emits a code create event.
|
||||
void CodeCreateEvent(LogEventsAndTags tag,
|
||||
Code* code, const char* source);
|
||||
void CodeCreateEvent(LogEventsAndTags tag,
|
||||
Code* code, String* name);
|
||||
Code* code, Name* name);
|
||||
void CodeCreateEvent(LogEventsAndTags tag,
|
||||
Code* code,
|
||||
SharedFunctionInfo* shared,
|
||||
String* name);
|
||||
Name* name);
|
||||
void CodeCreateEvent(LogEventsAndTags tag,
|
||||
Code* code,
|
||||
SharedFunctionInfo* shared,
|
||||
String* source, int line);
|
||||
Name* source, int line);
|
||||
void CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count);
|
||||
void CodeMovingGCEvent();
|
||||
// Emits a code create event for a RegExp.
|
||||
@ -395,7 +395,7 @@ class Logger {
|
||||
|
||||
// Emits callback event messages.
|
||||
void CallbackEventInternal(const char* prefix,
|
||||
const char* name,
|
||||
Name* name,
|
||||
Address entry_point);
|
||||
|
||||
// Internal configurable move event.
|
||||
|
@ -922,7 +922,7 @@ void JSObject::IncrementSpillStatistics(SpillInformation* info) {
|
||||
info->number_of_fast_used_fields_ += map()->NextFreePropertyIndex();
|
||||
info->number_of_fast_unused_fields_ += map()->unused_property_fields();
|
||||
} else {
|
||||
StringDictionary* dict = property_dictionary();
|
||||
NameDictionary* dict = property_dictionary();
|
||||
info->number_of_slow_used_properties_ += dict->NumberOfElements();
|
||||
info->number_of_slow_unused_properties_ +=
|
||||
dict->Capacity() - dict->NumberOfElements();
|
||||
@ -1013,10 +1013,10 @@ void JSObject::SpillInformation::Print() {
|
||||
|
||||
bool DescriptorArray::IsSortedNoDuplicates(int valid_entries) {
|
||||
if (valid_entries == -1) valid_entries = number_of_descriptors();
|
||||
String* current_key = NULL;
|
||||
Name* current_key = NULL;
|
||||
uint32_t current = 0;
|
||||
for (int i = 0; i < number_of_descriptors(); i++) {
|
||||
String* key = GetSortedKey(i);
|
||||
Name* key = GetSortedKey(i);
|
||||
if (key == current_key) {
|
||||
PrintDescriptors();
|
||||
return false;
|
||||
@ -1035,10 +1035,10 @@ bool DescriptorArray::IsSortedNoDuplicates(int valid_entries) {
|
||||
|
||||
bool TransitionArray::IsSortedNoDuplicates(int valid_entries) {
|
||||
ASSERT(valid_entries == -1);
|
||||
String* current_key = NULL;
|
||||
Name* current_key = NULL;
|
||||
uint32_t current = 0;
|
||||
for (int i = 0; i < number_of_transitions(); i++) {
|
||||
String* key = GetSortedKey(i);
|
||||
Name* key = GetSortedKey(i);
|
||||
if (key == current_key) {
|
||||
PrintTransitions();
|
||||
return false;
|
||||
|
@ -902,13 +902,13 @@ Object* Object::GetElementNoExceptionThrown(uint32_t index) {
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Object::GetProperty(String* key) {
|
||||
MaybeObject* Object::GetProperty(Name* key) {
|
||||
PropertyAttributes attributes;
|
||||
return GetPropertyWithReceiver(this, key, &attributes);
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Object::GetProperty(String* key, PropertyAttributes* attributes) {
|
||||
MaybeObject* Object::GetProperty(Name* key, PropertyAttributes* attributes) {
|
||||
return GetPropertyWithReceiver(this, key, attributes);
|
||||
}
|
||||
|
||||
@ -1493,7 +1493,7 @@ MaybeObject* JSObject::AddFastPropertyUsingMap(Map* map) {
|
||||
|
||||
|
||||
bool JSObject::TryTransitionToField(Handle<JSObject> object,
|
||||
Handle<String> key) {
|
||||
Handle<Name> key) {
|
||||
if (!object->map()->HasTransitionArray()) return false;
|
||||
Handle<TransitionArray> transitions(object->map()->transitions());
|
||||
int transition = transitions->Search(*key);
|
||||
@ -2021,7 +2021,7 @@ void DescriptorArray::SetNumberOfDescriptors(int number_of_descriptors) {
|
||||
// there are three entries in this array it should be called with low=0 and
|
||||
// high=2.
|
||||
template<SearchMode search_mode, typename T>
|
||||
int BinarySearch(T* array, String* name, int low, int high, int valid_entries) {
|
||||
int BinarySearch(T* array, Name* name, int low, int high, int valid_entries) {
|
||||
uint32_t hash = name->Hash();
|
||||
int limit = high;
|
||||
|
||||
@ -2029,7 +2029,7 @@ int BinarySearch(T* array, String* name, int low, int high, int valid_entries) {
|
||||
|
||||
while (low != high) {
|
||||
int mid = (low + high) / 2;
|
||||
String* mid_name = array->GetSortedKey(mid);
|
||||
Name* mid_name = array->GetSortedKey(mid);
|
||||
uint32_t mid_hash = mid_name->Hash();
|
||||
|
||||
if (mid_hash >= hash) {
|
||||
@ -2041,7 +2041,7 @@ int BinarySearch(T* array, String* name, int low, int high, int valid_entries) {
|
||||
|
||||
for (; low <= limit; ++low) {
|
||||
int sort_index = array->GetSortedKeyIndex(low);
|
||||
String* entry = array->GetKey(sort_index);
|
||||
Name* entry = array->GetKey(sort_index);
|
||||
if (entry->Hash() != hash) break;
|
||||
if (entry->Equals(name)) {
|
||||
if (search_mode == ALL_ENTRIES || sort_index < valid_entries) {
|
||||
@ -2058,12 +2058,12 @@ int BinarySearch(T* array, String* name, int low, int high, int valid_entries) {
|
||||
// Perform a linear search in this fixed array. len is the number of entry
|
||||
// indices that are valid.
|
||||
template<SearchMode search_mode, typename T>
|
||||
int LinearSearch(T* array, String* name, int len, int valid_entries) {
|
||||
int LinearSearch(T* array, Name* name, int len, int valid_entries) {
|
||||
uint32_t hash = name->Hash();
|
||||
if (search_mode == ALL_ENTRIES) {
|
||||
for (int number = 0; number < len; number++) {
|
||||
int sorted_index = array->GetSortedKeyIndex(number);
|
||||
String* entry = array->GetKey(sorted_index);
|
||||
Name* entry = array->GetKey(sorted_index);
|
||||
uint32_t current_hash = entry->Hash();
|
||||
if (current_hash > hash) break;
|
||||
if (current_hash == hash && entry->Equals(name)) return sorted_index;
|
||||
@ -2071,7 +2071,7 @@ int LinearSearch(T* array, String* name, int len, int valid_entries) {
|
||||
} else {
|
||||
ASSERT(len >= valid_entries);
|
||||
for (int number = 0; number < valid_entries; number++) {
|
||||
String* entry = array->GetKey(number);
|
||||
Name* entry = array->GetKey(number);
|
||||
uint32_t current_hash = entry->Hash();
|
||||
if (current_hash == hash && entry->Equals(name)) return number;
|
||||
}
|
||||
@ -2081,7 +2081,7 @@ int LinearSearch(T* array, String* name, int len, int valid_entries) {
|
||||
|
||||
|
||||
template<SearchMode search_mode, typename T>
|
||||
int Search(T* array, String* name, int valid_entries) {
|
||||
int Search(T* array, Name* name, int valid_entries) {
|
||||
if (search_mode == VALID_ENTRIES) {
|
||||
SLOW_ASSERT(array->IsSortedNoDuplicates(valid_entries));
|
||||
} else {
|
||||
@ -2105,12 +2105,12 @@ int Search(T* array, String* name, int valid_entries) {
|
||||
}
|
||||
|
||||
|
||||
int DescriptorArray::Search(String* name, int valid_descriptors) {
|
||||
int DescriptorArray::Search(Name* name, int valid_descriptors) {
|
||||
return internal::Search<VALID_ENTRIES>(this, name, valid_descriptors);
|
||||
}
|
||||
|
||||
|
||||
int DescriptorArray::SearchWithCache(String* name, Map* map) {
|
||||
int DescriptorArray::SearchWithCache(Name* name, Map* map) {
|
||||
int number_of_own_descriptors = map->NumberOfOwnDescriptors();
|
||||
if (number_of_own_descriptors == 0) return kNotFound;
|
||||
|
||||
@ -2127,7 +2127,7 @@ int DescriptorArray::SearchWithCache(String* name, Map* map) {
|
||||
|
||||
|
||||
void Map::LookupDescriptor(JSObject* holder,
|
||||
String* name,
|
||||
Name* name,
|
||||
LookupResult* result) {
|
||||
DescriptorArray* descriptors = this->instance_descriptors();
|
||||
int number = descriptors->SearchWithCache(name, this);
|
||||
@ -2137,7 +2137,7 @@ void Map::LookupDescriptor(JSObject* holder,
|
||||
|
||||
|
||||
void Map::LookupTransition(JSObject* holder,
|
||||
String* name,
|
||||
Name* name,
|
||||
LookupResult* result) {
|
||||
if (HasTransitionArray()) {
|
||||
TransitionArray* transition_array = transitions();
|
||||
@ -2168,9 +2168,9 @@ Object** DescriptorArray::GetDescriptorEndSlot(int descriptor_number) {
|
||||
}
|
||||
|
||||
|
||||
String* DescriptorArray::GetKey(int descriptor_number) {
|
||||
Name* DescriptorArray::GetKey(int descriptor_number) {
|
||||
ASSERT(descriptor_number < number_of_descriptors());
|
||||
return String::cast(get(ToKeyIndex(descriptor_number)));
|
||||
return Name::cast(get(ToKeyIndex(descriptor_number)));
|
||||
}
|
||||
|
||||
|
||||
@ -2179,7 +2179,7 @@ int DescriptorArray::GetSortedKeyIndex(int descriptor_number) {
|
||||
}
|
||||
|
||||
|
||||
String* DescriptorArray::GetSortedKey(int descriptor_number) {
|
||||
Name* DescriptorArray::GetSortedKey(int descriptor_number) {
|
||||
return GetKey(GetSortedKeyIndex(descriptor_number));
|
||||
}
|
||||
|
||||
@ -2293,7 +2293,7 @@ void DescriptorArray::Append(Descriptor* desc,
|
||||
int insertion;
|
||||
|
||||
for (insertion = descriptor_number; insertion > 0; --insertion) {
|
||||
String* key = GetSortedKey(insertion - 1);
|
||||
Name* key = GetSortedKey(insertion - 1);
|
||||
if (key->Hash() <= hash) break;
|
||||
SetSortedKey(insertion, GetSortedKeyIndex(insertion - 1));
|
||||
}
|
||||
@ -2314,7 +2314,7 @@ void DescriptorArray::Append(Descriptor* desc) {
|
||||
int insertion;
|
||||
|
||||
for (insertion = descriptor_number; insertion > 0; --insertion) {
|
||||
String* key = GetSortedKey(insertion - 1);
|
||||
Name* key = GetSortedKey(insertion - 1);
|
||||
if (key->Hash() <= hash) break;
|
||||
SetSortedKey(insertion, GetSortedKeyIndex(insertion - 1));
|
||||
}
|
||||
@ -2428,12 +2428,12 @@ CAST_ACCESSOR(ExternalString)
|
||||
CAST_ACCESSOR(ExternalAsciiString)
|
||||
CAST_ACCESSOR(ExternalTwoByteString)
|
||||
CAST_ACCESSOR(Symbol)
|
||||
CAST_ACCESSOR(Name)
|
||||
CAST_ACCESSOR(JSReceiver)
|
||||
CAST_ACCESSOR(JSObject)
|
||||
CAST_ACCESSOR(Smi)
|
||||
CAST_ACCESSOR(HeapObject)
|
||||
CAST_ACCESSOR(HeapNumber)
|
||||
CAST_ACCESSOR(Name)
|
||||
CAST_ACCESSOR(Oddball)
|
||||
CAST_ACCESSOR(JSGlobalPropertyCell)
|
||||
CAST_ACCESSOR(SharedFunctionInfo)
|
||||
@ -2499,10 +2499,16 @@ void Name::set_hash_field(uint32_t value) {
|
||||
}
|
||||
|
||||
|
||||
bool Name::Equals(Name* other) {
|
||||
if (other == this) return true;
|
||||
if (this->IsUniqueName() && other->IsUniqueName()) return false;
|
||||
return String::cast(this)->SlowEquals(String::cast(other));
|
||||
}
|
||||
|
||||
|
||||
bool String::Equals(String* other) {
|
||||
if (other == this) return true;
|
||||
if (StringShape(this).IsInternalized() &&
|
||||
StringShape(other).IsInternalized()) {
|
||||
if (this->IsInternalizedString() && other->IsInternalizedString()) {
|
||||
return false;
|
||||
}
|
||||
return SlowEquals(other);
|
||||
@ -3231,7 +3237,7 @@ int Map::pre_allocated_property_fields() {
|
||||
int HeapObject::SizeFromMap(Map* map) {
|
||||
int instance_size = map->instance_size();
|
||||
if (instance_size != kVariableSizeSentinel) return instance_size;
|
||||
// We can ignore the "internalized" bit becase it is only set for strings
|
||||
// We can ignore the "internalized" bit because it is only set for strings
|
||||
// and thus implies a string type.
|
||||
int instance_type =
|
||||
static_cast<int>(map->instance_type()) & ~kIsInternalizedMask;
|
||||
@ -4013,7 +4019,7 @@ bool Map::CanHaveMoreTransitions() {
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Map::AddTransition(String* key,
|
||||
MaybeObject* Map::AddTransition(Name* key,
|
||||
Map* target,
|
||||
SimpleTransitionFlag flag) {
|
||||
if (HasTransitionArray()) return transitions()->CopyInsert(key, target);
|
||||
@ -5262,9 +5268,9 @@ MaybeObject* JSObject::EnsureWritableFastElements() {
|
||||
}
|
||||
|
||||
|
||||
StringDictionary* JSObject::property_dictionary() {
|
||||
NameDictionary* JSObject::property_dictionary() {
|
||||
ASSERT(!HasFastProperties());
|
||||
return StringDictionary::cast(properties());
|
||||
return NameDictionary::cast(properties());
|
||||
}
|
||||
|
||||
|
||||
@ -5387,6 +5393,11 @@ uint32_t StringHasher::HashSequentialString(const schar* chars,
|
||||
}
|
||||
|
||||
|
||||
bool Name::AsArrayIndex(uint32_t* index) {
|
||||
return IsString() && String::cast(this)->AsArrayIndex(index);
|
||||
}
|
||||
|
||||
|
||||
bool String::AsArrayIndex(uint32_t* index) {
|
||||
uint32_t field = hash_field();
|
||||
if (IsHashFieldComputed(field) && (field & kIsNotArrayIndexMask)) {
|
||||
@ -5406,7 +5417,7 @@ Object* JSReceiver::GetConstructor() {
|
||||
}
|
||||
|
||||
|
||||
bool JSReceiver::HasProperty(String* name) {
|
||||
bool JSReceiver::HasProperty(Name* name) {
|
||||
if (IsJSProxy()) {
|
||||
return JSProxy::cast(this)->HasPropertyWithHandler(name);
|
||||
}
|
||||
@ -5414,7 +5425,7 @@ bool JSReceiver::HasProperty(String* name) {
|
||||
}
|
||||
|
||||
|
||||
bool JSReceiver::HasLocalProperty(String* name) {
|
||||
bool JSReceiver::HasLocalProperty(Name* name) {
|
||||
if (IsJSProxy()) {
|
||||
return JSProxy::cast(this)->HasPropertyWithHandler(name);
|
||||
}
|
||||
@ -5422,7 +5433,7 @@ bool JSReceiver::HasLocalProperty(String* name) {
|
||||
}
|
||||
|
||||
|
||||
PropertyAttributes JSReceiver::GetPropertyAttribute(String* key) {
|
||||
PropertyAttributes JSReceiver::GetPropertyAttribute(Name* key) {
|
||||
uint32_t index;
|
||||
if (IsJSObject() && key->AsArrayIndex(&index)) {
|
||||
return GetElementAttribute(index);
|
||||
@ -5547,7 +5558,7 @@ void Dictionary<Shape, Key>::SetEntry(int entry,
|
||||
Object* key,
|
||||
Object* value,
|
||||
PropertyDetails details) {
|
||||
ASSERT(!key->IsString() ||
|
||||
ASSERT(!key->IsName() ||
|
||||
details.IsDeleted() ||
|
||||
details.dictionary_index() > 0);
|
||||
int index = HashTable<Shape, Key>::EntryToIndex(entry);
|
||||
@ -5592,25 +5603,25 @@ MaybeObject* NumberDictionaryShape::AsObject(uint32_t key) {
|
||||
}
|
||||
|
||||
|
||||
bool StringDictionaryShape::IsMatch(String* key, Object* other) {
|
||||
bool NameDictionaryShape::IsMatch(Name* key, Object* other) {
|
||||
// We know that all entries in a hash table had their hash keys created.
|
||||
// Use that knowledge to have fast failure.
|
||||
if (key->Hash() != String::cast(other)->Hash()) return false;
|
||||
return key->Equals(String::cast(other));
|
||||
if (key->Hash() != Name::cast(other)->Hash()) return false;
|
||||
return key->Equals(Name::cast(other));
|
||||
}
|
||||
|
||||
|
||||
uint32_t StringDictionaryShape::Hash(String* key) {
|
||||
uint32_t NameDictionaryShape::Hash(Name* key) {
|
||||
return key->Hash();
|
||||
}
|
||||
|
||||
|
||||
uint32_t StringDictionaryShape::HashForObject(String* key, Object* other) {
|
||||
return String::cast(other)->Hash();
|
||||
uint32_t NameDictionaryShape::HashForObject(Name* key, Object* other) {
|
||||
return Name::cast(other)->Hash();
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* StringDictionaryShape::AsObject(String* key) {
|
||||
MaybeObject* NameDictionaryShape::AsObject(Name* key) {
|
||||
return key;
|
||||
}
|
||||
|
||||
|
@ -259,7 +259,7 @@ void JSObject::PrintProperties(FILE* out) {
|
||||
DescriptorArray* descs = map()->instance_descriptors();
|
||||
for (int i = 0; i < map()->NumberOfOwnDescriptors(); i++) {
|
||||
PrintF(out, " ");
|
||||
descs->GetKey(i)->StringPrint(out);
|
||||
descs->GetKey(i)->NamePrint(out);
|
||||
PrintF(out, ": ");
|
||||
switch (descs->GetType(i)) {
|
||||
case FIELD: {
|
||||
@ -417,7 +417,7 @@ void JSObject::PrintTransitions(FILE* out) {
|
||||
TransitionArray* transitions = map()->transitions();
|
||||
for (int i = 0; i < transitions->number_of_transitions(); i++) {
|
||||
PrintF(out, " ");
|
||||
transitions->GetKey(i)->StringPrint(out);
|
||||
transitions->GetKey(i)->NamePrint(out);
|
||||
PrintF(out, ": ");
|
||||
switch (transitions->GetTargetDetails(i).type()) {
|
||||
case FIELD: {
|
||||
@ -710,6 +710,14 @@ void String::StringPrint(FILE* out) {
|
||||
}
|
||||
|
||||
|
||||
void Name::NamePrint(FILE* out) {
|
||||
if (IsString())
|
||||
String::cast(this)->StringPrint(out);
|
||||
else
|
||||
ShortPrint();
|
||||
}
|
||||
|
||||
|
||||
// This method is only meant to be called from gdb for debugging purposes.
|
||||
// Since the string can also be in two-byte encoding, non-ASCII characters
|
||||
// will be ignored in the output.
|
||||
@ -1136,7 +1144,7 @@ void TransitionArray::PrintTransitions(FILE* out) {
|
||||
PrintF(out, "Transition array %d\n", number_of_transitions());
|
||||
for (int i = 0; i < number_of_transitions(); i++) {
|
||||
PrintF(out, " %d: ", i);
|
||||
GetKey(i)->StringPrint(out);
|
||||
GetKey(i)->NamePrint(out);
|
||||
PrintF(out, ": ");
|
||||
switch (GetTargetDetails(i).type()) {
|
||||
case FIELD: {
|
||||
|
436
src/objects.cc
436
src/objects.cc
File diff suppressed because it is too large
Load Diff
252
src/objects.h
252
src/objects.h
@ -936,8 +936,6 @@ class MaybeObject BASE_EMBEDDED {
|
||||
V(ObjectHashTable) \
|
||||
|
||||
|
||||
class JSReceiver;
|
||||
|
||||
// Object is the abstract superclass for all classes in the
|
||||
// object hierarchy.
|
||||
// Object does not use any virtual functions to avoid the
|
||||
@ -1003,28 +1001,28 @@ class Object : public MaybeObject {
|
||||
// Failure is returned otherwise.
|
||||
MUST_USE_RESULT inline MaybeObject* ToSmi();
|
||||
|
||||
void Lookup(String* name, LookupResult* result);
|
||||
void Lookup(Name* name, LookupResult* result);
|
||||
|
||||
// Property access.
|
||||
MUST_USE_RESULT inline MaybeObject* GetProperty(String* key);
|
||||
MUST_USE_RESULT inline MaybeObject* GetProperty(Name* key);
|
||||
MUST_USE_RESULT inline MaybeObject* GetProperty(
|
||||
String* key,
|
||||
Name* key,
|
||||
PropertyAttributes* attributes);
|
||||
MUST_USE_RESULT MaybeObject* GetPropertyWithReceiver(
|
||||
Object* receiver,
|
||||
String* key,
|
||||
Name* key,
|
||||
PropertyAttributes* attributes);
|
||||
|
||||
static Handle<Object> GetProperty(Handle<Object> object, Handle<String> key);
|
||||
static Handle<Object> GetProperty(Handle<Object> object, Handle<Name> key);
|
||||
static Handle<Object> GetProperty(Handle<Object> object,
|
||||
Handle<Object> receiver,
|
||||
LookupResult* result,
|
||||
Handle<String> key,
|
||||
Handle<Name> key,
|
||||
PropertyAttributes* attributes);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* GetProperty(Object* receiver,
|
||||
LookupResult* result,
|
||||
String* key,
|
||||
Name* key,
|
||||
PropertyAttributes* attributes);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* GetPropertyWithDefinedGetter(Object* receiver,
|
||||
@ -1491,20 +1489,20 @@ class JSReceiver: public HeapObject {
|
||||
static inline JSReceiver* cast(Object* obj);
|
||||
|
||||
static Handle<Object> SetProperty(Handle<JSReceiver> object,
|
||||
Handle<String> key,
|
||||
Handle<Name> key,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes,
|
||||
StrictModeFlag strict_mode);
|
||||
// Can cause GC.
|
||||
MUST_USE_RESULT MaybeObject* SetProperty(
|
||||
String* key,
|
||||
Name* key,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
StrictModeFlag strict_mode,
|
||||
StoreFromKeyed store_from_keyed = MAY_BE_STORE_FROM_KEYED);
|
||||
MUST_USE_RESULT MaybeObject* SetProperty(
|
||||
LookupResult* result,
|
||||
String* key,
|
||||
Name* key,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
StrictModeFlag strict_mode,
|
||||
@ -1512,7 +1510,7 @@ class JSReceiver: public HeapObject {
|
||||
MUST_USE_RESULT MaybeObject* SetPropertyWithDefinedSetter(JSReceiver* setter,
|
||||
Object* value);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode mode);
|
||||
MUST_USE_RESULT MaybeObject* DeleteProperty(Name* name, DeleteMode mode);
|
||||
MUST_USE_RESULT MaybeObject* DeleteElement(uint32_t index, DeleteMode mode);
|
||||
|
||||
// Set the index'th array element.
|
||||
@ -1533,17 +1531,17 @@ class JSReceiver: public HeapObject {
|
||||
// function that was used to instantiate the object).
|
||||
String* constructor_name();
|
||||
|
||||
inline PropertyAttributes GetPropertyAttribute(String* name);
|
||||
inline PropertyAttributes GetPropertyAttribute(Name* name);
|
||||
PropertyAttributes GetPropertyAttributeWithReceiver(JSReceiver* receiver,
|
||||
String* name);
|
||||
PropertyAttributes GetLocalPropertyAttribute(String* name);
|
||||
Name* name);
|
||||
PropertyAttributes GetLocalPropertyAttribute(Name* name);
|
||||
|
||||
inline PropertyAttributes GetElementAttribute(uint32_t index);
|
||||
inline PropertyAttributes GetLocalElementAttribute(uint32_t index);
|
||||
|
||||
// Can cause a GC.
|
||||
inline bool HasProperty(String* name);
|
||||
inline bool HasLocalProperty(String* name);
|
||||
inline bool HasProperty(Name* name);
|
||||
inline bool HasLocalProperty(Name* name);
|
||||
inline bool HasElement(uint32_t index);
|
||||
inline bool HasLocalElement(uint32_t index);
|
||||
|
||||
@ -1563,9 +1561,9 @@ class JSReceiver: public HeapObject {
|
||||
|
||||
// Lookup a property. If found, the result is valid and has
|
||||
// detailed information.
|
||||
void LocalLookup(String* name, LookupResult* result,
|
||||
void LocalLookup(Name* name, LookupResult* result,
|
||||
bool search_hidden_prototypes = false);
|
||||
void Lookup(String* name, LookupResult* result);
|
||||
void Lookup(Name* name, LookupResult* result);
|
||||
|
||||
protected:
|
||||
Smi* GenerateIdentityHash();
|
||||
@ -1573,7 +1571,7 @@ class JSReceiver: public HeapObject {
|
||||
private:
|
||||
PropertyAttributes GetPropertyAttributeForResult(JSReceiver* receiver,
|
||||
LookupResult* result,
|
||||
String* name,
|
||||
Name* name,
|
||||
bool continue_search);
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(JSReceiver);
|
||||
@ -1591,7 +1589,7 @@ class JSObject: public JSReceiver {
|
||||
DECL_ACCESSORS(properties, FixedArray) // Get and set fast properties.
|
||||
inline void initialize_properties();
|
||||
inline bool HasFastProperties();
|
||||
inline StringDictionary* property_dictionary(); // Gets slow properties.
|
||||
inline NameDictionary* property_dictionary(); // Gets slow properties.
|
||||
|
||||
// [elements]: The elements (properties with names that are integers).
|
||||
//
|
||||
@ -1665,34 +1663,34 @@ class JSObject: public JSReceiver {
|
||||
|
||||
MUST_USE_RESULT MaybeObject* GetPropertyWithCallback(Object* receiver,
|
||||
Object* structure,
|
||||
String* name);
|
||||
Name* name);
|
||||
|
||||
// Can cause GC.
|
||||
MUST_USE_RESULT MaybeObject* SetPropertyForResult(LookupResult* result,
|
||||
String* key,
|
||||
Name* key,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
StrictModeFlag strict_mode,
|
||||
StoreFromKeyed store_mode);
|
||||
MUST_USE_RESULT MaybeObject* SetPropertyWithFailedAccessCheck(
|
||||
LookupResult* result,
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* value,
|
||||
bool check_prototype,
|
||||
StrictModeFlag strict_mode);
|
||||
MUST_USE_RESULT MaybeObject* SetPropertyWithCallback(
|
||||
Object* structure,
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* value,
|
||||
JSObject* holder,
|
||||
StrictModeFlag strict_mode);
|
||||
MUST_USE_RESULT MaybeObject* SetPropertyWithInterceptor(
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
StrictModeFlag strict_mode);
|
||||
MUST_USE_RESULT MaybeObject* SetPropertyPostInterceptor(
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
StrictModeFlag strict_mode,
|
||||
@ -1700,14 +1698,14 @@ class JSObject: public JSReceiver {
|
||||
|
||||
static Handle<Object> SetLocalPropertyIgnoreAttributes(
|
||||
Handle<JSObject> object,
|
||||
Handle<String> key,
|
||||
Handle<Name> key,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
// Try to follow an existing transition to a field with attributes NONE. The
|
||||
// return value indicates whether the transition was successful.
|
||||
static inline bool TryTransitionToField(Handle<JSObject> object,
|
||||
Handle<String> key);
|
||||
Handle<Name> key);
|
||||
|
||||
inline int LastAddedFieldIndex();
|
||||
|
||||
@ -1718,7 +1716,7 @@ class JSObject: public JSReceiver {
|
||||
|
||||
// Can cause GC.
|
||||
MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes(
|
||||
String* key,
|
||||
Name* key,
|
||||
Object* value,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
@ -1733,16 +1731,16 @@ class JSObject: public JSReceiver {
|
||||
// Sets the property value in a normalized object given (key, value, details).
|
||||
// Handles the special representation of JS global objects.
|
||||
static Handle<Object> SetNormalizedProperty(Handle<JSObject> object,
|
||||
Handle<String> key,
|
||||
Handle<Name> key,
|
||||
Handle<Object> value,
|
||||
PropertyDetails details);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* SetNormalizedProperty(String* name,
|
||||
MUST_USE_RESULT MaybeObject* SetNormalizedProperty(Name* name,
|
||||
Object* value,
|
||||
PropertyDetails details);
|
||||
|
||||
// Deletes the named property in a normalized object.
|
||||
MUST_USE_RESULT MaybeObject* DeleteNormalizedProperty(String* name,
|
||||
MUST_USE_RESULT MaybeObject* DeleteNormalizedProperty(Name* name,
|
||||
DeleteMode mode);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* OptimizeAsPrototype();
|
||||
@ -1753,27 +1751,27 @@ class JSObject: public JSReceiver {
|
||||
|
||||
// Used from JSReceiver.
|
||||
PropertyAttributes GetPropertyAttributePostInterceptor(JSObject* receiver,
|
||||
String* name,
|
||||
Name* name,
|
||||
bool continue_search);
|
||||
PropertyAttributes GetPropertyAttributeWithInterceptor(JSObject* receiver,
|
||||
String* name,
|
||||
Name* name,
|
||||
bool continue_search);
|
||||
PropertyAttributes GetPropertyAttributeWithFailedAccessCheck(
|
||||
Object* receiver,
|
||||
LookupResult* result,
|
||||
String* name,
|
||||
Name* name,
|
||||
bool continue_search);
|
||||
PropertyAttributes GetElementAttributeWithReceiver(JSReceiver* receiver,
|
||||
uint32_t index,
|
||||
bool continue_search);
|
||||
|
||||
static void DefineAccessor(Handle<JSObject> object,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<Object> getter,
|
||||
Handle<Object> setter,
|
||||
PropertyAttributes attributes);
|
||||
// Can cause GC.
|
||||
MUST_USE_RESULT MaybeObject* DefineAccessor(String* name,
|
||||
MUST_USE_RESULT MaybeObject* DefineAccessor(Name* name,
|
||||
Object* getter,
|
||||
Object* setter,
|
||||
PropertyAttributes attributes);
|
||||
@ -1781,11 +1779,11 @@ class JSObject: public JSReceiver {
|
||||
// Returns a JavaScript null if this was not possible and we have to use the
|
||||
// slow case. Note that we can fail due to allocations, too.
|
||||
MUST_USE_RESULT MaybeObject* DefineFastAccessor(
|
||||
String* name,
|
||||
Name* name,
|
||||
AccessorComponent component,
|
||||
Object* accessor,
|
||||
PropertyAttributes attributes);
|
||||
Object* LookupAccessor(String* name, AccessorComponent component);
|
||||
Object* LookupAccessor(Name* name, AccessorComponent component);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* DefineAccessor(AccessorInfo* info);
|
||||
|
||||
@ -1793,19 +1791,19 @@ class JSObject: public JSReceiver {
|
||||
MUST_USE_RESULT MaybeObject* GetPropertyWithFailedAccessCheck(
|
||||
Object* receiver,
|
||||
LookupResult* result,
|
||||
String* name,
|
||||
Name* name,
|
||||
PropertyAttributes* attributes);
|
||||
MUST_USE_RESULT MaybeObject* GetPropertyWithInterceptor(
|
||||
Object* receiver,
|
||||
String* name,
|
||||
Name* name,
|
||||
PropertyAttributes* attributes);
|
||||
MUST_USE_RESULT MaybeObject* GetPropertyPostInterceptor(
|
||||
Object* receiver,
|
||||
String* name,
|
||||
Name* name,
|
||||
PropertyAttributes* attributes);
|
||||
MUST_USE_RESULT MaybeObject* GetLocalPropertyPostInterceptor(
|
||||
Object* receiver,
|
||||
String* name,
|
||||
Name* name,
|
||||
PropertyAttributes* attributes);
|
||||
|
||||
// Returns true if this is an instance of an api function and has
|
||||
@ -1828,17 +1826,17 @@ class JSObject: public JSReceiver {
|
||||
// Sets a hidden property on this object. Returns this object if successful,
|
||||
// undefined if called on a detached proxy.
|
||||
static Handle<Object> SetHiddenProperty(Handle<JSObject> obj,
|
||||
Handle<String> key,
|
||||
Handle<Name> key,
|
||||
Handle<Object> value);
|
||||
// Returns a failure if a GC is required.
|
||||
MUST_USE_RESULT MaybeObject* SetHiddenProperty(String* key, Object* value);
|
||||
MUST_USE_RESULT MaybeObject* SetHiddenProperty(Name* key, Object* value);
|
||||
// Gets the value of a hidden property with the given key. Returns undefined
|
||||
// if the property doesn't exist (or if called on a detached proxy),
|
||||
// otherwise returns the value set for the key.
|
||||
Object* GetHiddenProperty(String* key);
|
||||
Object* GetHiddenProperty(Name* key);
|
||||
// Deletes a hidden property. Deleting a non-existing property is
|
||||
// considered successful.
|
||||
void DeleteHiddenProperty(String* key);
|
||||
void DeleteHiddenProperty(Name* key);
|
||||
// Returns true if the object has a property with the hidden string as name.
|
||||
bool HasHiddenProperties();
|
||||
|
||||
@ -1847,9 +1845,9 @@ class JSObject: public JSReceiver {
|
||||
MUST_USE_RESULT MaybeObject* SetIdentityHash(Smi* hash, CreationFlag flag);
|
||||
|
||||
static Handle<Object> DeleteProperty(Handle<JSObject> obj,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
// Can cause GC.
|
||||
MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode mode);
|
||||
MUST_USE_RESULT MaybeObject* DeleteProperty(Name* name, DeleteMode mode);
|
||||
|
||||
static Handle<Object> DeleteElement(Handle<JSObject> obj, uint32_t index);
|
||||
MUST_USE_RESULT MaybeObject* DeleteElement(uint32_t index, DeleteMode mode);
|
||||
@ -1893,11 +1891,11 @@ class JSObject: public JSReceiver {
|
||||
return old_capacity + (old_capacity >> 1) + 16;
|
||||
}
|
||||
|
||||
PropertyType GetLocalPropertyType(String* name);
|
||||
PropertyType GetLocalPropertyType(Name* name);
|
||||
PropertyType GetLocalElementType(uint32_t index);
|
||||
|
||||
// These methods do not perform access checks!
|
||||
AccessorPair* GetLocalPropertyAccessorPair(String* name);
|
||||
AccessorPair* GetLocalPropertyAccessorPair(Name* name);
|
||||
AccessorPair* GetLocalElementAccessorPair(uint32_t index);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* SetFastElement(uint32_t index,
|
||||
@ -1970,9 +1968,9 @@ class JSObject: public JSReceiver {
|
||||
inline bool HasIndexedInterceptor();
|
||||
|
||||
// Support functions for v8 api (needed for correct interceptor behavior).
|
||||
bool HasRealNamedProperty(String* key);
|
||||
bool HasRealNamedProperty(Name* key);
|
||||
bool HasRealElementProperty(uint32_t index);
|
||||
bool HasRealNamedCallbackProperty(String* key);
|
||||
bool HasRealNamedCallbackProperty(Name* key);
|
||||
|
||||
// Get the header size for a JSObject. Used to compute the index of
|
||||
// internal fields as well as the number of internal fields.
|
||||
@ -1985,12 +1983,12 @@ class JSObject: public JSReceiver {
|
||||
inline void SetInternalField(int index, Smi* value);
|
||||
|
||||
// The following lookup functions skip interceptors.
|
||||
void LocalLookupRealNamedProperty(String* name, LookupResult* result);
|
||||
void LookupRealNamedProperty(String* name, LookupResult* result);
|
||||
void LookupRealNamedPropertyInPrototypes(String* name, LookupResult* result);
|
||||
void LocalLookupRealNamedProperty(Name* name, LookupResult* result);
|
||||
void LookupRealNamedProperty(Name* name, LookupResult* result);
|
||||
void LookupRealNamedPropertyInPrototypes(Name* name, LookupResult* result);
|
||||
MUST_USE_RESULT MaybeObject* SetElementWithCallbackSetterInPrototypes(
|
||||
uint32_t index, Object* value, bool* found, StrictModeFlag strict_mode);
|
||||
void LookupCallbackProperty(String* name, LookupResult* result);
|
||||
void LookupCallbackProperty(Name* name, LookupResult* result);
|
||||
|
||||
// Returns the number of properties on this object filtering out properties
|
||||
// with the specified attributes (ignoring interceptors).
|
||||
@ -2017,7 +2015,7 @@ class JSObject: public JSReceiver {
|
||||
// Add a property to a fast-case object using a map transition to
|
||||
// new_map.
|
||||
MUST_USE_RESULT MaybeObject* AddFastPropertyUsingMap(Map* new_map,
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* value,
|
||||
int field_index);
|
||||
|
||||
@ -2028,12 +2026,12 @@ class JSObject: public JSReceiver {
|
||||
// This avoids the creation of many maps with the same constant
|
||||
// function, all orphaned.
|
||||
MUST_USE_RESULT MaybeObject* AddConstantFunctionProperty(
|
||||
String* name,
|
||||
Name* name,
|
||||
JSFunction* function,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* ReplaceSlowProperty(
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
@ -2057,32 +2055,32 @@ class JSObject: public JSReceiver {
|
||||
// Replaces an existing transition with a transition to a map with a FIELD.
|
||||
MUST_USE_RESULT MaybeObject* ConvertTransitionToMapTransition(
|
||||
int transition_index,
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* new_value,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
// Converts a descriptor of any other type to a real field, backed by the
|
||||
// properties array.
|
||||
MUST_USE_RESULT MaybeObject* ConvertDescriptorToField(
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* new_value,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
// Add a property to a fast-case object.
|
||||
MUST_USE_RESULT MaybeObject* AddFastProperty(
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED);
|
||||
|
||||
// Add a property to a slow-case object.
|
||||
MUST_USE_RESULT MaybeObject* AddSlowProperty(String* name,
|
||||
MUST_USE_RESULT MaybeObject* AddSlowProperty(Name* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
// Add a property to an object. May cause GC.
|
||||
MUST_USE_RESULT MaybeObject* AddProperty(
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
StrictModeFlag strict_mode,
|
||||
@ -2109,10 +2107,10 @@ class JSObject: public JSReceiver {
|
||||
MUST_USE_RESULT MaybeObject* NormalizeElements();
|
||||
|
||||
static void UpdateMapCodeCache(Handle<JSObject> object,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<Code> code);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* UpdateMapCodeCache(String* name, Code* code);
|
||||
MUST_USE_RESULT MaybeObject* UpdateMapCodeCache(Name* name, Code* code);
|
||||
|
||||
// Transform slow named properties to fast variants.
|
||||
// Returns failure if allocation failed.
|
||||
@ -2249,7 +2247,7 @@ class JSObject: public JSReceiver {
|
||||
// Enqueue change record for Object.observe. May cause GC.
|
||||
static void EnqueueChangeRecord(Handle<JSObject> object,
|
||||
const char* type,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<Object> old_value);
|
||||
|
||||
// Deliver change records to observers. May cause GC.
|
||||
@ -2296,15 +2294,15 @@ class JSObject: public JSReceiver {
|
||||
// read-only, reject and set '*done' to true. Otherwise, set '*done' to
|
||||
// false. Can cause GC and can return a failure result with '*done==true'.
|
||||
MUST_USE_RESULT MaybeObject* SetPropertyViaPrototypes(
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
StrictModeFlag strict_mode,
|
||||
bool* done);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* DeletePropertyPostInterceptor(String* name,
|
||||
MUST_USE_RESULT MaybeObject* DeletePropertyPostInterceptor(Name* name,
|
||||
DeleteMode mode);
|
||||
MUST_USE_RESULT MaybeObject* DeletePropertyWithInterceptor(String* name);
|
||||
MUST_USE_RESULT MaybeObject* DeletePropertyWithInterceptor(Name* name);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* DeleteElementWithInterceptor(uint32_t index);
|
||||
|
||||
@ -2322,13 +2320,13 @@ class JSObject: public JSReceiver {
|
||||
// Gets the current elements capacity and the number of used elements.
|
||||
void GetElementsCapacityAndUsage(int* capacity, int* used);
|
||||
|
||||
bool CanSetCallback(String* name);
|
||||
bool CanSetCallback(Name* name);
|
||||
MUST_USE_RESULT MaybeObject* SetElementCallback(
|
||||
uint32_t index,
|
||||
Object* structure,
|
||||
PropertyAttributes attributes);
|
||||
MUST_USE_RESULT MaybeObject* SetPropertyCallback(
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* structure,
|
||||
PropertyAttributes attributes);
|
||||
MUST_USE_RESULT MaybeObject* DefineElementAccessor(
|
||||
@ -2336,9 +2334,9 @@ class JSObject: public JSReceiver {
|
||||
Object* getter,
|
||||
Object* setter,
|
||||
PropertyAttributes attributes);
|
||||
MUST_USE_RESULT MaybeObject* CreateAccessorPairFor(String* name);
|
||||
MUST_USE_RESULT MaybeObject* CreateAccessorPairFor(Name* name);
|
||||
MUST_USE_RESULT MaybeObject* DefinePropertyAccessor(
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* getter,
|
||||
Object* setter,
|
||||
PropertyAttributes attributes);
|
||||
@ -2639,7 +2637,7 @@ class DescriptorArray: public FixedArray {
|
||||
Object* new_index_cache);
|
||||
|
||||
// Accessors for fetching instance descriptor at descriptor number.
|
||||
inline String* GetKey(int descriptor_number);
|
||||
inline Name* GetKey(int descriptor_number);
|
||||
inline Object** GetKeySlot(int descriptor_number);
|
||||
inline Object* GetValue(int descriptor_number);
|
||||
inline Object** GetValueSlot(int descriptor_number);
|
||||
@ -2652,7 +2650,7 @@ class DescriptorArray: public FixedArray {
|
||||
inline Object* GetCallbacksObject(int descriptor_number);
|
||||
inline AccessorDescriptor* GetCallbacks(int descriptor_number);
|
||||
|
||||
inline String* GetSortedKey(int descriptor_number);
|
||||
inline Name* GetSortedKey(int descriptor_number);
|
||||
inline int GetSortedKeyIndex(int descriptor_number);
|
||||
inline void SetSortedKey(int pointer, int descriptor_number);
|
||||
|
||||
@ -2682,11 +2680,11 @@ class DescriptorArray: public FixedArray {
|
||||
void Sort();
|
||||
|
||||
// Search the instance descriptors for given name.
|
||||
INLINE(int Search(String* name, int number_of_own_descriptors));
|
||||
INLINE(int Search(Name* name, int number_of_own_descriptors));
|
||||
|
||||
// As the above, but uses DescriptorLookupCache and updates it when
|
||||
// necessary.
|
||||
INLINE(int SearchWithCache(String* name, Map* map));
|
||||
INLINE(int SearchWithCache(Name* name, Map* map));
|
||||
|
||||
// Allocates a DescriptorArray, but returns the singleton
|
||||
// empty descriptor array object if number_of_descriptors is 0.
|
||||
@ -2795,11 +2793,11 @@ class DescriptorArray: public FixedArray {
|
||||
enum SearchMode { ALL_ENTRIES, VALID_ENTRIES };
|
||||
|
||||
template<SearchMode search_mode, typename T>
|
||||
inline int LinearSearch(T* array, String* name, int len, int valid_entries);
|
||||
inline int LinearSearch(T* array, Name* name, int len, int valid_entries);
|
||||
|
||||
|
||||
template<SearchMode search_mode, typename T>
|
||||
inline int Search(T* array, String* name, int valid_entries = 0);
|
||||
inline int Search(T* array, Name* name, int valid_entries = 0);
|
||||
|
||||
|
||||
// HashTable is a subclass of FixedArray that implements a hash table
|
||||
@ -3127,11 +3125,11 @@ class MapCacheShape : public BaseShape<HashTableKey*> {
|
||||
|
||||
// MapCache.
|
||||
//
|
||||
// Maps keys that are a fixed array of internalized strings to a map.
|
||||
// Maps keys that are a fixed array of unique names to a map.
|
||||
// Used for canonicalize maps for object literals.
|
||||
class MapCache: public HashTable<MapCacheShape, HashTableKey*> {
|
||||
public:
|
||||
// Find cached value for a string key, otherwise return null.
|
||||
// Find cached value for a name key, otherwise return null.
|
||||
Object* Lookup(FixedArray* key);
|
||||
MUST_USE_RESULT MaybeObject* Put(FixedArray* key, Map* value);
|
||||
static inline MapCache* cast(Object* obj);
|
||||
@ -3250,29 +3248,29 @@ class Dictionary: public HashTable<Shape, Key> {
|
||||
};
|
||||
|
||||
|
||||
class StringDictionaryShape : public BaseShape<String*> {
|
||||
class NameDictionaryShape : public BaseShape<Name*> {
|
||||
public:
|
||||
static inline bool IsMatch(String* key, Object* other);
|
||||
static inline uint32_t Hash(String* key);
|
||||
static inline uint32_t HashForObject(String* key, Object* object);
|
||||
MUST_USE_RESULT static inline MaybeObject* AsObject(String* key);
|
||||
static inline bool IsMatch(Name* key, Object* other);
|
||||
static inline uint32_t Hash(Name* key);
|
||||
static inline uint32_t HashForObject(Name* key, Object* object);
|
||||
MUST_USE_RESULT static inline MaybeObject* AsObject(Name* key);
|
||||
static const int kPrefixSize = 2;
|
||||
static const int kEntrySize = 3;
|
||||
static const bool kIsEnumerable = true;
|
||||
};
|
||||
|
||||
|
||||
class StringDictionary: public Dictionary<StringDictionaryShape, String*> {
|
||||
class NameDictionary: public Dictionary<NameDictionaryShape, Name*> {
|
||||
public:
|
||||
static inline StringDictionary* cast(Object* obj) {
|
||||
static inline NameDictionary* cast(Object* obj) {
|
||||
ASSERT(obj->IsDictionary());
|
||||
return reinterpret_cast<StringDictionary*>(obj);
|
||||
return reinterpret_cast<NameDictionary*>(obj);
|
||||
}
|
||||
|
||||
// Copies enumerable keys to preallocated fixed array.
|
||||
FixedArray* CopyEnumKeysTo(FixedArray* storage);
|
||||
static void DoGenerateNewEnumerationIndices(
|
||||
Handle<StringDictionary> dictionary);
|
||||
Handle<NameDictionary> dictionary);
|
||||
|
||||
// For transforming properties of a JSObject.
|
||||
MUST_USE_RESULT MaybeObject* TransformPropertiesToFastFor(
|
||||
@ -3281,7 +3279,7 @@ class StringDictionary: public Dictionary<StringDictionaryShape, String*> {
|
||||
|
||||
// Find entry for key, otherwise return kNotFound. Optimized version of
|
||||
// HashTable::FindEntry.
|
||||
int FindEntry(String* key);
|
||||
int FindEntry(Name* key);
|
||||
};
|
||||
|
||||
|
||||
@ -4993,7 +4991,7 @@ class Map: public HeapObject {
|
||||
Map* transitioned_map);
|
||||
inline void SetTransition(int transition_index, Map* target);
|
||||
inline Map* GetTransition(int transition_index);
|
||||
MUST_USE_RESULT inline MaybeObject* AddTransition(String* key,
|
||||
MUST_USE_RESULT inline MaybeObject* AddTransition(Name* key,
|
||||
Map* target,
|
||||
SimpleTransitionFlag flag);
|
||||
DECL_ACCESSORS(transitions, TransitionArray)
|
||||
@ -5091,11 +5089,11 @@ class Map: public HeapObject {
|
||||
// with the given holder if the name is found. The holder may be
|
||||
// NULL when this function is used from the compiler.
|
||||
inline void LookupDescriptor(JSObject* holder,
|
||||
String* name,
|
||||
Name* name,
|
||||
LookupResult* result);
|
||||
|
||||
inline void LookupTransition(JSObject* holder,
|
||||
String* name,
|
||||
Name* name,
|
||||
LookupResult* result);
|
||||
|
||||
// The size of transition arrays are limited so they do not end up in large
|
||||
@ -5144,7 +5142,7 @@ class Map: public HeapObject {
|
||||
MUST_USE_RESULT MaybeObject* CopyDropDescriptors();
|
||||
MUST_USE_RESULT MaybeObject* CopyReplaceDescriptors(
|
||||
DescriptorArray* descriptors,
|
||||
String* name,
|
||||
Name* name,
|
||||
TransitionFlag flag,
|
||||
int descriptor_index);
|
||||
MUST_USE_RESULT MaybeObject* ShareDescriptor(DescriptorArray* descriptors,
|
||||
@ -5172,7 +5170,7 @@ class Map: public HeapObject {
|
||||
MUST_USE_RESULT MaybeObject* Copy();
|
||||
|
||||
// Returns the property index for name (only valid for FAST MODE).
|
||||
int PropertyIndexFor(String* name);
|
||||
int PropertyIndexFor(Name* name);
|
||||
|
||||
// Returns the next free property index (only valid for FAST MODE).
|
||||
int NextFreePropertyIndex();
|
||||
@ -5186,7 +5184,7 @@ class Map: public HeapObject {
|
||||
static inline Map* cast(Object* obj);
|
||||
|
||||
// Locate an accessor in the instance descriptor.
|
||||
AccessorDescriptor* FindAccessor(String* name);
|
||||
AccessorDescriptor* FindAccessor(Name* name);
|
||||
|
||||
// Code cache operations.
|
||||
|
||||
@ -5195,9 +5193,9 @@ class Map: public HeapObject {
|
||||
|
||||
// Update code cache.
|
||||
static void UpdateCodeCache(Handle<Map> map,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<Code> code);
|
||||
MUST_USE_RESULT MaybeObject* UpdateCodeCache(String* name, Code* code);
|
||||
MUST_USE_RESULT MaybeObject* UpdateCodeCache(Name* name, Code* code);
|
||||
|
||||
// Extend the descriptor array of the map with the list of descriptors.
|
||||
// In case of duplicates, the latest descriptor is used.
|
||||
@ -5207,14 +5205,14 @@ class Map: public HeapObject {
|
||||
static void EnsureDescriptorSlack(Handle<Map> map, int slack);
|
||||
|
||||
// Returns the found code or undefined if absent.
|
||||
Object* FindInCodeCache(String* name, Code::Flags flags);
|
||||
Object* FindInCodeCache(Name* name, Code::Flags flags);
|
||||
|
||||
// Returns the non-negative index of the code object if it is in the
|
||||
// cache and -1 otherwise.
|
||||
int IndexInCodeCache(Object* name, Code* code);
|
||||
|
||||
// Removes a code object from the code cache at the given index.
|
||||
void RemoveFromCodeCache(String* name, Code* code, int index);
|
||||
void RemoveFromCodeCache(Name* name, Code* code, int index);
|
||||
|
||||
// Set all map transitions from this map to dead maps to null. Also clear
|
||||
// back pointers in transition targets so that we do not process this map
|
||||
@ -6434,7 +6432,7 @@ class GlobalObject: public JSObject {
|
||||
// by throwing an exception. This is for the debug and builtins global
|
||||
// objects, where it is known which properties can be expected to be present
|
||||
// on the object.
|
||||
Object* GetPropertyNoExceptionThrown(String* key) {
|
||||
Object* GetPropertyNoExceptionThrown(Name* key) {
|
||||
Object* answer = GetProperty(key)->ToObjectUnchecked();
|
||||
return answer;
|
||||
}
|
||||
@ -6442,10 +6440,10 @@ 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);
|
||||
Handle<Name> name);
|
||||
// TODO(kmillikin): This function can be eliminated once the stub cache is
|
||||
// fully handlified (and the static helper can be written directly).
|
||||
MUST_USE_RESULT MaybeObject* EnsurePropertyCell(String* name);
|
||||
MUST_USE_RESULT MaybeObject* EnsurePropertyCell(Name* name);
|
||||
|
||||
// Casting.
|
||||
static inline GlobalObject* cast(Object* obj);
|
||||
@ -6896,11 +6894,11 @@ class CodeCache: public Struct {
|
||||
DECL_ACCESSORS(normal_type_cache, Object)
|
||||
|
||||
// Add the code object to the cache.
|
||||
MUST_USE_RESULT MaybeObject* Update(String* name, Code* code);
|
||||
MUST_USE_RESULT MaybeObject* Update(Name* name, Code* code);
|
||||
|
||||
// Lookup code object in the cache. Returns code object if found and undefined
|
||||
// if not.
|
||||
Object* Lookup(String* name, Code::Flags flags);
|
||||
Object* Lookup(Name* name, Code::Flags flags);
|
||||
|
||||
// Get the internal index of a code object in the cache. Returns -1 if the
|
||||
// code object is not in that cache. This index can be used to later call
|
||||
@ -6923,10 +6921,10 @@ class CodeCache: public Struct {
|
||||
static const int kSize = kNormalTypeCacheOffset + kPointerSize;
|
||||
|
||||
private:
|
||||
MUST_USE_RESULT MaybeObject* UpdateDefaultCache(String* name, Code* code);
|
||||
MUST_USE_RESULT MaybeObject* UpdateNormalTypeCache(String* name, Code* code);
|
||||
Object* LookupDefaultCache(String* name, Code::Flags flags);
|
||||
Object* LookupNormalTypeCache(String* name, Code::Flags flags);
|
||||
MUST_USE_RESULT MaybeObject* UpdateDefaultCache(Name* name, Code* code);
|
||||
MUST_USE_RESULT MaybeObject* UpdateNormalTypeCache(Name* name, Code* code);
|
||||
Object* LookupDefaultCache(Name* name, Code::Flags flags);
|
||||
Object* LookupNormalTypeCache(Name* name, Code::Flags flags);
|
||||
|
||||
// Code cache layout of the default cache. Elements are alternating name and
|
||||
// code objects for non normal load/store/call IC's.
|
||||
@ -6964,10 +6962,10 @@ class CodeCacheHashTableShape : public BaseShape<HashTableKey*> {
|
||||
class CodeCacheHashTable: public HashTable<CodeCacheHashTableShape,
|
||||
HashTableKey*> {
|
||||
public:
|
||||
Object* Lookup(String* name, Code::Flags flags);
|
||||
MUST_USE_RESULT MaybeObject* Put(String* name, Code* code);
|
||||
Object* Lookup(Name* name, Code::Flags flags);
|
||||
MUST_USE_RESULT MaybeObject* Put(Name* name, Code* code);
|
||||
|
||||
int GetIndex(String* name, Code::Flags flags);
|
||||
int GetIndex(Name* name, Code::Flags flags);
|
||||
void RemoveByIndex(int index);
|
||||
|
||||
static inline CodeCacheHashTable* cast(Object* obj);
|
||||
@ -7254,9 +7252,17 @@ class Name: public HeapObject {
|
||||
// Returns a hash value used for the property table
|
||||
inline uint32_t Hash();
|
||||
|
||||
// Equality operations.
|
||||
inline bool Equals(Name* other);
|
||||
|
||||
// Conversion.
|
||||
inline bool AsArrayIndex(uint32_t* index);
|
||||
|
||||
// Casting.
|
||||
static inline Name* cast(Object* obj);
|
||||
|
||||
DECLARE_PRINTER(Name)
|
||||
|
||||
// Layout description.
|
||||
static const int kHashFieldOffset = HeapObject::kHeaderSize;
|
||||
static const int kSize = kHashFieldOffset + kPointerSize;
|
||||
@ -8180,19 +8186,19 @@ class JSProxy: public JSReceiver {
|
||||
// Casting.
|
||||
static inline JSProxy* cast(Object* obj);
|
||||
|
||||
bool HasPropertyWithHandler(String* name);
|
||||
bool HasPropertyWithHandler(Name* name);
|
||||
bool HasElementWithHandler(uint32_t index);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* GetPropertyWithHandler(
|
||||
Object* receiver,
|
||||
String* name);
|
||||
Name* name);
|
||||
MUST_USE_RESULT MaybeObject* GetElementWithHandler(
|
||||
Object* receiver,
|
||||
uint32_t index);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* SetPropertyWithHandler(
|
||||
JSReceiver* receiver,
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
StrictModeFlag strict_mode);
|
||||
@ -8208,14 +8214,14 @@ class JSProxy: public JSReceiver {
|
||||
// otherwise set it to false.
|
||||
MUST_USE_RESULT MaybeObject* SetPropertyViaPrototypesWithHandler(
|
||||
JSReceiver* receiver,
|
||||
String* name,
|
||||
Name* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
StrictModeFlag strict_mode,
|
||||
bool* done);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* DeletePropertyWithHandler(
|
||||
String* name,
|
||||
Name* name,
|
||||
DeleteMode mode);
|
||||
MUST_USE_RESULT MaybeObject* DeleteElementWithHandler(
|
||||
uint32_t index,
|
||||
@ -8223,7 +8229,7 @@ class JSProxy: public JSReceiver {
|
||||
|
||||
MUST_USE_RESULT PropertyAttributes GetPropertyAttributeWithHandler(
|
||||
JSReceiver* receiver,
|
||||
String* name);
|
||||
Name* name);
|
||||
MUST_USE_RESULT PropertyAttributes GetElementAttributeWithHandler(
|
||||
JSReceiver* receiver,
|
||||
uint32_t index);
|
||||
|
@ -33,7 +33,7 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
const char* StringsStorage::GetFunctionName(String* name) {
|
||||
const char* StringsStorage::GetFunctionName(Name* name) {
|
||||
return GetFunctionName(GetName(name));
|
||||
}
|
||||
|
||||
|
@ -153,14 +153,17 @@ const char* StringsStorage::GetVFormatted(const char* format, va_list args) {
|
||||
}
|
||||
|
||||
|
||||
const char* StringsStorage::GetName(String* name) {
|
||||
const char* StringsStorage::GetName(Name* name) {
|
||||
if (name->IsString()) {
|
||||
int length = Min(kMaxNameSize, name->length());
|
||||
String* str = String::cast(name);
|
||||
int length = Min(kMaxNameSize, str->length());
|
||||
SmartArrayPointer<char> data =
|
||||
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, 0, length);
|
||||
str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, 0, length);
|
||||
uint32_t hash = StringHasher::HashSequentialString(
|
||||
*data, length, name->GetHeap()->HashSeed());
|
||||
return AddOrDisposeString(data.Detach(), hash);
|
||||
} else if (name->IsSymbol()) {
|
||||
return "<symbol>";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@ -782,7 +785,7 @@ List<CpuProfile*>* CpuProfilesCollection::Profiles(int security_token_id) {
|
||||
|
||||
|
||||
CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
|
||||
String* name,
|
||||
Name* name,
|
||||
String* resource_name,
|
||||
int line_number) {
|
||||
CodeEntry* entry = new CodeEntry(tag,
|
||||
@ -811,7 +814,7 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
|
||||
|
||||
CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
|
||||
const char* name_prefix,
|
||||
String* name) {
|
||||
Name* name) {
|
||||
CodeEntry* entry = new CodeEntry(tag,
|
||||
name_prefix,
|
||||
GetName(name),
|
||||
|
@ -69,9 +69,9 @@ class StringsStorage {
|
||||
const char* GetCopy(const char* src);
|
||||
const char* GetFormatted(const char* format, ...);
|
||||
const char* GetVFormatted(const char* format, va_list args);
|
||||
const char* GetName(String* name);
|
||||
const char* GetName(Name* name);
|
||||
const char* GetName(int index);
|
||||
inline const char* GetFunctionName(String* name);
|
||||
inline const char* GetFunctionName(Name* name);
|
||||
inline const char* GetFunctionName(const char* name);
|
||||
size_t GetUsedMemorySize() const;
|
||||
|
||||
@ -296,7 +296,7 @@ class CpuProfilesCollection {
|
||||
const char* title,
|
||||
double actual_sampling_rate);
|
||||
List<CpuProfile*>* Profiles(int security_token_id);
|
||||
const char* GetName(String* name) {
|
||||
const char* GetName(Name* name) {
|
||||
return function_and_resource_names_.GetName(name);
|
||||
}
|
||||
const char* GetName(int args_count) {
|
||||
@ -308,10 +308,10 @@ class CpuProfilesCollection {
|
||||
bool HasDetachedProfiles() { return detached_profiles_.length() > 0; }
|
||||
|
||||
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
|
||||
String* name, String* resource_name, int line_number);
|
||||
Name* name, String* resource_name, int line_number);
|
||||
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, const char* name);
|
||||
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
|
||||
const char* name_prefix, String* name);
|
||||
const char* name_prefix, Name* name);
|
||||
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count);
|
||||
CodeEntry* NewCodeEntry(int security_token_id);
|
||||
|
||||
@ -322,7 +322,7 @@ class CpuProfilesCollection {
|
||||
static const int kMaxSimultaneousProfiles = 100;
|
||||
|
||||
private:
|
||||
const char* GetFunctionName(String* name) {
|
||||
const char* GetFunctionName(Name* name) {
|
||||
return function_and_resource_names_.GetFunctionName(name);
|
||||
}
|
||||
const char* GetFunctionName(const char* name) {
|
||||
@ -395,7 +395,7 @@ class ProfileGenerator {
|
||||
explicit ProfileGenerator(CpuProfilesCollection* profiles);
|
||||
|
||||
INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
|
||||
String* name,
|
||||
Name* name,
|
||||
String* resource_name,
|
||||
int line_number)) {
|
||||
return profiles_->NewCodeEntry(tag, name, resource_name, line_number);
|
||||
@ -408,7 +408,7 @@ class ProfileGenerator {
|
||||
|
||||
INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
|
||||
const char* name_prefix,
|
||||
String* name)) {
|
||||
Name* name)) {
|
||||
return profiles_->NewCodeEntry(tag, name_prefix, name);
|
||||
}
|
||||
|
||||
|
@ -48,15 +48,15 @@ class Descriptor BASE_EMBEDDED {
|
||||
return Smi::cast(value)->value();
|
||||
}
|
||||
|
||||
MUST_USE_RESULT MaybeObject* KeyToInternalizedString() {
|
||||
if (!StringShape(key_).IsInternalized()) {
|
||||
MaybeObject* maybe_result = HEAP->InternalizeString(key_);
|
||||
MUST_USE_RESULT MaybeObject* KeyToUniqueName() {
|
||||
if (!key_->IsUniqueName()) {
|
||||
MaybeObject* maybe_result = HEAP->InternalizeString(String::cast(key_));
|
||||
if (!maybe_result->To(&key_)) return maybe_result;
|
||||
}
|
||||
return key_;
|
||||
}
|
||||
|
||||
String* GetKey() { return key_; }
|
||||
Name* GetKey() { return key_; }
|
||||
Object* GetValue() { return value_; }
|
||||
PropertyDetails GetDetails() { return details_; }
|
||||
|
||||
@ -71,25 +71,25 @@ class Descriptor BASE_EMBEDDED {
|
||||
void SetSortedKeyIndex(int index) { details_ = details_.set_pointer(index); }
|
||||
|
||||
private:
|
||||
String* key_;
|
||||
Name* key_;
|
||||
Object* value_;
|
||||
PropertyDetails details_;
|
||||
|
||||
protected:
|
||||
Descriptor() : details_(Smi::FromInt(0)) {}
|
||||
|
||||
void Init(String* key, Object* value, PropertyDetails details) {
|
||||
void Init(Name* key, Object* value, PropertyDetails details) {
|
||||
key_ = key;
|
||||
value_ = value;
|
||||
details_ = details;
|
||||
}
|
||||
|
||||
Descriptor(String* key, Object* value, PropertyDetails details)
|
||||
Descriptor(Name* key, Object* value, PropertyDetails details)
|
||||
: key_(key),
|
||||
value_(value),
|
||||
details_(details) { }
|
||||
|
||||
Descriptor(String* key,
|
||||
Descriptor(Name* key,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
PropertyType type,
|
||||
@ -104,7 +104,7 @@ class Descriptor BASE_EMBEDDED {
|
||||
|
||||
class FieldDescriptor: public Descriptor {
|
||||
public:
|
||||
FieldDescriptor(String* key,
|
||||
FieldDescriptor(Name* key,
|
||||
int field_index,
|
||||
PropertyAttributes attributes,
|
||||
int index = 0)
|
||||
@ -114,7 +114,7 @@ class FieldDescriptor: public Descriptor {
|
||||
|
||||
class ConstantFunctionDescriptor: public Descriptor {
|
||||
public:
|
||||
ConstantFunctionDescriptor(String* key,
|
||||
ConstantFunctionDescriptor(Name* key,
|
||||
JSFunction* function,
|
||||
PropertyAttributes attributes,
|
||||
int index)
|
||||
@ -124,7 +124,7 @@ class ConstantFunctionDescriptor: public Descriptor {
|
||||
|
||||
class CallbacksDescriptor: public Descriptor {
|
||||
public:
|
||||
CallbacksDescriptor(String* key,
|
||||
CallbacksDescriptor(Name* key,
|
||||
Object* foreign,
|
||||
PropertyAttributes attributes,
|
||||
int index = 0)
|
||||
|
@ -189,6 +189,6 @@ function ProxyEnumerate(proxy) {
|
||||
if (IS_UNDEFINED(handler.enumerate)) {
|
||||
return %Apply(DerivedEnumerateTrap, handler, [], 0, 0)
|
||||
} else {
|
||||
return ToStringArray(handler.enumerate(), "enumerate")
|
||||
return ToNameArray(handler.enumerate(), "enumerate")
|
||||
}
|
||||
}
|
||||
|
113
src/runtime.cc
113
src/runtime.cc
@ -1049,7 +1049,7 @@ static AccessCheckResult CheckElementAccess(
|
||||
|
||||
static AccessCheckResult CheckPropertyAccess(
|
||||
JSObject* obj,
|
||||
String* name,
|
||||
Name* name,
|
||||
v8::AccessType access_type) {
|
||||
uint32_t index;
|
||||
if (name->AsArrayIndex(&index)) {
|
||||
@ -1109,7 +1109,7 @@ enum PropertyDescriptorIndices {
|
||||
|
||||
static MaybeObject* GetOwnProperty(Isolate* isolate,
|
||||
Handle<JSObject> obj,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
Heap* heap = isolate->heap();
|
||||
// Due to some WebKit tests, we want to make sure that we do not log
|
||||
// more than one access failure here.
|
||||
@ -1163,7 +1163,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
|
||||
ASSERT(args.length() == 2);
|
||||
HandleScope scope(isolate);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
||||
return GetOwnProperty(isolate, obj, name);
|
||||
}
|
||||
|
||||
@ -2119,7 +2119,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
|
||||
} else { // Dictionary properties.
|
||||
// Directly manipulate the property details.
|
||||
int entry = function->property_dictionary()->FindEntry(name);
|
||||
ASSERT(entry != StringDictionary::kNotFound);
|
||||
ASSERT(entry != NameDictionary::kNotFound);
|
||||
PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
|
||||
PropertyDetails new_details(
|
||||
static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
|
||||
@ -3898,16 +3898,16 @@ MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
|
||||
return GetElementOrCharAt(isolate, object, index);
|
||||
}
|
||||
|
||||
// Convert the key to a string - possibly by calling back into JavaScript.
|
||||
Handle<String> name;
|
||||
if (key->IsString()) {
|
||||
name = Handle<String>::cast(key);
|
||||
// Convert the key to a name - possibly by calling back into JavaScript.
|
||||
Handle<Name> name;
|
||||
if (key->IsName()) {
|
||||
name = Handle<Name>::cast(key);
|
||||
} else {
|
||||
bool has_pending_exception = false;
|
||||
Handle<Object> converted =
|
||||
Execution::ToString(key, &has_pending_exception);
|
||||
if (has_pending_exception) return Failure::Exception();
|
||||
name = Handle<String>::cast(converted);
|
||||
name = Handle<Name>::cast(converted);
|
||||
}
|
||||
|
||||
// Check if the name is trivially convertible to an index and get
|
||||
@ -3931,7 +3931,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
|
||||
}
|
||||
|
||||
|
||||
// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
|
||||
// KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
|
||||
NoHandleAllocation ha(isolate);
|
||||
ASSERT(args.length() == 2);
|
||||
@ -3950,9 +3950,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
|
||||
if (args[0]->IsJSObject()) {
|
||||
if (!args[0]->IsJSGlobalProxy() &&
|
||||
!args[0]->IsAccessCheckNeeded() &&
|
||||
args[1]->IsString()) {
|
||||
args[1]->IsName()) {
|
||||
JSObject* receiver = JSObject::cast(args[0]);
|
||||
String* key = String::cast(args[1]);
|
||||
Name* key = Name::cast(args[1]);
|
||||
if (receiver->HasFastProperties()) {
|
||||
// Attempt to use lookup cache.
|
||||
Map* receiver_map = receiver->map();
|
||||
@ -3975,9 +3975,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
|
||||
}
|
||||
} else {
|
||||
// Attempt dictionary lookup.
|
||||
StringDictionary* dictionary = receiver->property_dictionary();
|
||||
NameDictionary* dictionary = receiver->property_dictionary();
|
||||
int entry = dictionary->FindEntry(key);
|
||||
if ((entry != StringDictionary::kNotFound) &&
|
||||
if ((entry != NameDictionary::kNotFound) &&
|
||||
(dictionary->DetailsAt(entry).type() == NORMAL)) {
|
||||
Object* value = dictionary->ValueAt(entry);
|
||||
if (!receiver->IsGlobalObject()) return value;
|
||||
@ -3987,7 +3987,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
|
||||
}
|
||||
}
|
||||
} else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
|
||||
// JSObject without a string key. If the key is a Smi, check for a
|
||||
// JSObject without a name key. If the key is a Smi, check for a
|
||||
// definite out-of-bounds access to elements, which is a strong indicator
|
||||
// that subsequent accesses will also call the runtime. Proactively
|
||||
// transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
|
||||
@ -4047,7 +4047,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
|
||||
HandleScope scope(isolate);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
||||
RUNTIME_ASSERT(!obj->IsNull());
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
|
||||
RUNTIME_ASSERT(IsValidAccessor(getter));
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
|
||||
@ -4072,7 +4072,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
|
||||
ASSERT(args.length() == 4);
|
||||
HandleScope scope(isolate);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
|
||||
CONVERT_SMI_ARG_CHECKED(unchecked, 3);
|
||||
RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
|
||||
@ -4137,7 +4137,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDataProperty) {
|
||||
ASSERT(args.length() == 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, key, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
|
||||
LookupResult lookup(isolate);
|
||||
object->LookupRealNamedProperty(*key, &lookup);
|
||||
if (!lookup.IsFound()) return isolate->heap()->undefined_value();
|
||||
@ -4180,10 +4180,11 @@ MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
|
||||
|
||||
if (object->IsJSProxy()) {
|
||||
bool has_pending_exception = false;
|
||||
Handle<Object> name = Execution::ToString(key, &has_pending_exception);
|
||||
Handle<Object> name = key->IsSymbol()
|
||||
? key : Execution::ToString(key, &has_pending_exception);
|
||||
if (has_pending_exception) return Failure::Exception();
|
||||
return JSProxy::cast(*object)->SetProperty(
|
||||
String::cast(*name), *value, attr, strict_mode);
|
||||
Name::cast(*name), *value, attr, strict_mode);
|
||||
}
|
||||
|
||||
// If the object isn't a JavaScript object, we ignore the store.
|
||||
@ -4213,16 +4214,16 @@ MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
|
||||
return *value;
|
||||
}
|
||||
|
||||
if (key->IsString()) {
|
||||
if (key->IsName()) {
|
||||
Handle<Object> result;
|
||||
if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
|
||||
Handle<Name> name = Handle<Name>::cast(key);
|
||||
if (name->AsArrayIndex(&index)) {
|
||||
result = JSObject::SetElement(
|
||||
js_object, index, value, attr, strict_mode, set_mode);
|
||||
} else {
|
||||
Handle<String> key_string = Handle<String>::cast(key);
|
||||
key_string->TryFlatten();
|
||||
if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
|
||||
result = JSReceiver::SetProperty(
|
||||
js_object, key_string, value, attr, strict_mode);
|
||||
js_object, name, value, attr, strict_mode);
|
||||
}
|
||||
if (result.is_null()) return Failure::Exception();
|
||||
return *value;
|
||||
@ -4268,16 +4269,14 @@ MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
|
||||
index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
|
||||
}
|
||||
|
||||
if (key->IsString()) {
|
||||
if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
|
||||
if (key->IsName()) {
|
||||
Handle<Name> name = Handle<Name>::cast(key);
|
||||
if (name->AsArrayIndex(&index)) {
|
||||
return js_object->SetElement(
|
||||
index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
|
||||
} else {
|
||||
Handle<String> key_string = Handle<String>::cast(key);
|
||||
key_string->TryFlatten();
|
||||
return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
|
||||
*value,
|
||||
attr);
|
||||
if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
|
||||
return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4317,19 +4316,19 @@ MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
|
||||
return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
|
||||
}
|
||||
|
||||
Handle<String> key_string;
|
||||
if (key->IsString()) {
|
||||
key_string = Handle<String>::cast(key);
|
||||
Handle<Name> name;
|
||||
if (key->IsName()) {
|
||||
name = Handle<Name>::cast(key);
|
||||
} else {
|
||||
// Call-back into JavaScript to convert the key to a string.
|
||||
bool has_pending_exception = false;
|
||||
Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
|
||||
if (has_pending_exception) return Failure::Exception();
|
||||
key_string = Handle<String>::cast(converted);
|
||||
name = Handle<String>::cast(converted);
|
||||
}
|
||||
|
||||
key_string->TryFlatten();
|
||||
return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
|
||||
if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
|
||||
return receiver->DeleteProperty(*name, JSReceiver::FORCE_DELETION);
|
||||
}
|
||||
|
||||
|
||||
@ -4516,7 +4515,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
|
||||
NoHandleAllocation ha(isolate);
|
||||
RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
|
||||
CONVERT_ARG_CHECKED(JSObject, object, 0);
|
||||
CONVERT_ARG_CHECKED(String, name, 1);
|
||||
CONVERT_ARG_CHECKED(Name, name, 1);
|
||||
// Compute attributes.
|
||||
PropertyAttributes attributes = NONE;
|
||||
if (args.length() == 4) {
|
||||
@ -4537,7 +4536,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
|
||||
ASSERT(args.length() == 3);
|
||||
|
||||
CONVERT_ARG_CHECKED(JSReceiver, object, 0);
|
||||
CONVERT_ARG_CHECKED(String, key, 1);
|
||||
CONVERT_ARG_CHECKED(Name, key, 1);
|
||||
CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
|
||||
return object->DeleteProperty(key, (strict_mode == kStrictMode)
|
||||
? JSReceiver::STRICT_DELETION
|
||||
@ -4547,7 +4546,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
|
||||
|
||||
static Object* HasLocalPropertyImplementation(Isolate* isolate,
|
||||
Handle<JSObject> object,
|
||||
Handle<String> key) {
|
||||
Handle<Name> key) {
|
||||
if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
|
||||
// Handle hidden prototypes. If there's a hidden prototype above this thing
|
||||
// then we have to check it for properties, because they are supposed to
|
||||
@ -4566,7 +4565,7 @@ static Object* HasLocalPropertyImplementation(Isolate* isolate,
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
|
||||
NoHandleAllocation ha(isolate);
|
||||
ASSERT(args.length() == 2);
|
||||
CONVERT_ARG_CHECKED(String, key, 1);
|
||||
CONVERT_ARG_CHECKED(Name, key, 1);
|
||||
|
||||
uint32_t index;
|
||||
const bool key_is_array_index = key->AsArrayIndex(&index);
|
||||
@ -4589,7 +4588,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
|
||||
HandleScope scope(isolate);
|
||||
return HasLocalPropertyImplementation(isolate,
|
||||
Handle<JSObject>(object),
|
||||
Handle<String>(key));
|
||||
Handle<Name>(key));
|
||||
} else if (obj->IsString() && key_is_array_index) {
|
||||
// Well, there is one exception: Handle [] on strings.
|
||||
String* string = String::cast(obj);
|
||||
@ -4605,7 +4604,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
|
||||
NoHandleAllocation na(isolate);
|
||||
ASSERT(args.length() == 2);
|
||||
CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
|
||||
CONVERT_ARG_CHECKED(String, key, 1);
|
||||
CONVERT_ARG_CHECKED(Name, key, 1);
|
||||
|
||||
bool result = receiver->HasProperty(key);
|
||||
if (isolate->has_pending_exception()) return Failure::Exception();
|
||||
@ -4630,7 +4629,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
|
||||
ASSERT(args.length() == 2);
|
||||
|
||||
CONVERT_ARG_CHECKED(JSObject, object, 0);
|
||||
CONVERT_ARG_CHECKED(String, key, 1);
|
||||
CONVERT_ARG_CHECKED(Name, key, 1);
|
||||
|
||||
PropertyAttributes att = object->GetLocalPropertyAttribute(key);
|
||||
return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
|
||||
@ -4874,7 +4873,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
|
||||
Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object* entry = contents->get(i);
|
||||
if (entry->IsString()) {
|
||||
if (entry->IsName()) {
|
||||
copy->set(i, entry);
|
||||
} else {
|
||||
ASSERT(entry->IsNumber());
|
||||
@ -4908,6 +4907,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
|
||||
return frame->GetParameter(index);
|
||||
}
|
||||
|
||||
if (args[0]->IsSymbol()) {
|
||||
// Lookup in the initial Object.prototype object.
|
||||
return isolate->initial_object_prototype()->GetProperty(
|
||||
Symbol::cast(args[0]));
|
||||
}
|
||||
|
||||
// Convert the key to a string.
|
||||
HandleScope scope(isolate);
|
||||
bool exception = false;
|
||||
@ -9874,7 +9879,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
|
||||
ASSERT(args.length() == 3);
|
||||
CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
|
||||
CONVERT_ARG_CHECKED(String, name, 1);
|
||||
CONVERT_ARG_CHECKED(Name, name, 1);
|
||||
CONVERT_SMI_ARG_CHECKED(flag, 2);
|
||||
AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
|
||||
if (!receiver->IsJSObject()) return isolate->heap()->undefined_value();
|
||||
@ -9927,7 +9932,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
|
||||
|
||||
static MaybeObject* DebugLookupResultValue(Heap* heap,
|
||||
Object* receiver,
|
||||
String* name,
|
||||
Name* name,
|
||||
LookupResult* result,
|
||||
bool* caught_exception) {
|
||||
Object* value;
|
||||
@ -9999,7 +10004,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
|
||||
ASSERT(args.length() == 2);
|
||||
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
||||
|
||||
// Make sure to set the current context to the context before the debugger was
|
||||
// entered (if the debugger is entered). The reason for switching context here
|
||||
@ -10097,7 +10102,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
|
||||
ASSERT(args.length() == 2);
|
||||
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
||||
|
||||
LookupResult result(isolate);
|
||||
obj->Lookup(*name, &result);
|
||||
@ -10144,7 +10149,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
|
||||
ASSERT(args.length() == 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
|
||||
RUNTIME_ASSERT(obj->HasNamedInterceptor());
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
||||
|
||||
PropertyAttributes attributes;
|
||||
return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
|
||||
@ -13253,15 +13258,15 @@ MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
|
||||
Object* dictionary) {
|
||||
ASSERT(Isolate::Current()->heap() == heap);
|
||||
ASSERT(dictionary != NULL);
|
||||
ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
|
||||
ASSERT(NameDictionary::cast(dictionary)->NumberOfElements() == 0);
|
||||
for (int i = 0; i < kNumFunctions; ++i) {
|
||||
Object* name_string;
|
||||
{ MaybeObject* maybe_name_string =
|
||||
heap->InternalizeUtf8String(kIntrinsicFunctions[i].name);
|
||||
if (!maybe_name_string->ToObject(&name_string)) return maybe_name_string;
|
||||
}
|
||||
StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
|
||||
{ MaybeObject* maybe_dictionary = string_dictionary->Add(
|
||||
NameDictionary* name_dictionary = NameDictionary::cast(dictionary);
|
||||
{ MaybeObject* maybe_dictionary = name_dictionary->Add(
|
||||
String::cast(name_string),
|
||||
Smi::FromInt(i),
|
||||
PropertyDetails(NONE, NORMAL));
|
||||
|
@ -346,7 +346,7 @@ function SHR(y) {
|
||||
|
||||
// ECMA-262, section 11.4.1, page 46.
|
||||
function DELETE(key, strict) {
|
||||
return %DeleteProperty(%ToObject(this), %ToString(key), strict);
|
||||
return %DeleteProperty(%ToObject(this), %ToName(key), strict);
|
||||
}
|
||||
|
||||
|
||||
@ -356,7 +356,7 @@ function IN(x) {
|
||||
throw %MakeTypeError('invalid_in_operator_use', [this, x]);
|
||||
}
|
||||
return %_IsNonNegativeSmi(this) ?
|
||||
%HasElement(x, this) : %HasProperty(x, %ToString(this));
|
||||
%HasElement(x, this) : %HasProperty(x, %ToName(this));
|
||||
}
|
||||
|
||||
|
||||
@ -396,7 +396,7 @@ function INSTANCE_OF(F) {
|
||||
// has a property with the given key; return the key as a string if
|
||||
// it has. Otherwise returns 0 (smi). Used in for-in statements.
|
||||
function FILTER_KEY(key) {
|
||||
var string = %ToString(key);
|
||||
var string = %ToName(key);
|
||||
if (%HasProperty(this, string)) return string;
|
||||
return 0;
|
||||
}
|
||||
@ -563,6 +563,12 @@ function NonStringToString(x) {
|
||||
}
|
||||
|
||||
|
||||
// ES6 symbols
|
||||
function ToName(x) {
|
||||
return IS_SYMBOL(x) ? x : %ToString(x);
|
||||
}
|
||||
|
||||
|
||||
// ECMA-262, section 9.9, page 36.
|
||||
function ToObject(x) {
|
||||
if (IS_STRING(x)) return new $String(x);
|
||||
|
@ -56,14 +56,14 @@ void StubCache::Initialize() {
|
||||
}
|
||||
|
||||
|
||||
Code* StubCache::Set(String* name, Map* map, Code* code) {
|
||||
Code* StubCache::Set(Name* name, Map* map, Code* code) {
|
||||
// Get the flags from the code.
|
||||
Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
|
||||
|
||||
// Validate that the name does not move on scavenge, and that we
|
||||
// can use identity checks instead of string equality checks.
|
||||
// can use identity checks instead of structural equality checks.
|
||||
ASSERT(!heap()->InNewSpace(name));
|
||||
ASSERT(name->IsInternalizedString());
|
||||
ASSERT(name->IsUniqueName());
|
||||
|
||||
// The state bits are not important to the hash function because
|
||||
// the stub cache only contains monomorphic stubs. Make sure that
|
||||
@ -109,7 +109,7 @@ Handle<JSObject> StubCache::StubHolder(Handle<JSObject> receiver,
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::FindStub(Handle<String> name,
|
||||
Handle<Code> StubCache::FindStub(Handle<Name> name,
|
||||
Handle<JSObject> stub_holder,
|
||||
Code::Kind kind,
|
||||
Code::StubType type,
|
||||
@ -122,7 +122,7 @@ Handle<Code> StubCache::FindStub(Handle<String> name,
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::FindHandler(Handle<String> name,
|
||||
Handle<Code> StubCache::FindHandler(Handle<Name> name,
|
||||
Handle<JSObject> handler_holder,
|
||||
Code::Kind kind,
|
||||
Code::StubType type) {
|
||||
@ -132,7 +132,7 @@ Handle<Code> StubCache::FindHandler(Handle<String> name,
|
||||
|
||||
Handle<Code> StubCache::ComputeMonomorphicIC(Handle<JSObject> receiver,
|
||||
Handle<Code> handler,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
Handle<Code> ic = FindStub(name, receiver, Code::LOAD_IC,
|
||||
handler->type(), Code::IC_FRAGMENT);
|
||||
if (!ic.is_null()) return ic;
|
||||
@ -148,7 +148,7 @@ Handle<Code> StubCache::ComputeMonomorphicIC(Handle<JSObject> receiver,
|
||||
|
||||
Handle<Code> StubCache::ComputeKeyedMonomorphicIC(Handle<JSObject> receiver,
|
||||
Handle<Code> handler,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
Handle<Code> ic = FindStub(name, receiver, Code::KEYED_LOAD_IC,
|
||||
handler->type(), Code::IC_FRAGMENT);
|
||||
if (!ic.is_null()) return ic;
|
||||
@ -162,7 +162,7 @@ Handle<Code> StubCache::ComputeKeyedMonomorphicIC(Handle<JSObject> receiver,
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
|
||||
Handle<JSObject> receiver) {
|
||||
// If no global objects are present in the prototype chain, the load
|
||||
// nonexistent IC stub can be shared for all names for a given map
|
||||
@ -170,7 +170,7 @@ Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
|
||||
// there are global objects involved, we need to check global
|
||||
// property cells in the stub and therefore the stub will be
|
||||
// specific to the name.
|
||||
Handle<String> cache_name = factory()->empty_string();
|
||||
Handle<Name> cache_name = factory()->empty_string();
|
||||
Handle<JSObject> current;
|
||||
Handle<Object> next = receiver;
|
||||
Handle<GlobalObject> global;
|
||||
@ -199,7 +199,7 @@ Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeLoadField(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeLoadField(Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
PropertyIndex field) {
|
||||
@ -224,7 +224,7 @@ Handle<Code> StubCache::ComputeLoadField(Handle<String> name,
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeLoadCallback(
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
@ -242,7 +242,7 @@ Handle<Code> StubCache::ComputeLoadCallback(
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeLoadViaGetter(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeLoadViaGetter(Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> getter) {
|
||||
@ -259,7 +259,7 @@ Handle<Code> StubCache::ComputeLoadViaGetter(Handle<String> name,
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeLoadConstant(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeLoadConstant(Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> value) {
|
||||
@ -276,7 +276,7 @@ Handle<Code> StubCache::ComputeLoadConstant(Handle<String> name,
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeLoadInterceptor(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeLoadInterceptor(Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder) {
|
||||
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
|
||||
@ -292,13 +292,13 @@ Handle<Code> StubCache::ComputeLoadInterceptor(Handle<String> name,
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeLoadNormal(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeLoadNormal(Handle<Name> name,
|
||||
Handle<JSObject> receiver) {
|
||||
return isolate_->builtins()->LoadIC_Normal();
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeLoadGlobal(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeLoadGlobal(Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<GlobalObject> holder,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
@ -316,7 +316,7 @@ Handle<Code> StubCache::ComputeLoadGlobal(Handle<String> name,
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeKeyedLoadField(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeKeyedLoadField(Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
PropertyIndex field) {
|
||||
@ -340,7 +340,7 @@ Handle<Code> StubCache::ComputeKeyedLoadField(Handle<String> name,
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> value) {
|
||||
@ -356,7 +356,7 @@ Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<String> name,
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder) {
|
||||
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
|
||||
@ -373,7 +373,7 @@ Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<String> name,
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeKeyedLoadCallback(
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
@ -390,7 +390,7 @@ Handle<Code> StubCache::ComputeKeyedLoadCallback(
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeStoreField(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeStoreField(Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
int field_index,
|
||||
Handle<Map> transition,
|
||||
@ -413,7 +413,7 @@ Handle<Code> StubCache::ComputeStoreField(Handle<String> name,
|
||||
|
||||
Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) {
|
||||
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
|
||||
Handle<String> name =
|
||||
Handle<Name> name =
|
||||
isolate()->factory()->KeyedLoadElementMonomorphic_string();
|
||||
|
||||
Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
|
||||
@ -440,7 +440,7 @@ Handle<Code> StubCache::ComputeKeyedStoreElement(
|
||||
ASSERT(stub_kind == KeyedStoreIC::STORE_NO_TRANSITION ||
|
||||
stub_kind == KeyedStoreIC::STORE_AND_GROW_NO_TRANSITION);
|
||||
|
||||
Handle<String> name = stub_kind == KeyedStoreIC::STORE_NO_TRANSITION
|
||||
Handle<Name> name = stub_kind == KeyedStoreIC::STORE_NO_TRANSITION
|
||||
? isolate()->factory()->KeyedStoreElementMonomorphic_string()
|
||||
: isolate()->factory()->KeyedStoreAndGrowElementMonomorphic_string();
|
||||
|
||||
@ -462,7 +462,7 @@ Handle<Code> StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeStoreGlobal(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeStoreGlobal(Handle<Name> name,
|
||||
Handle<GlobalObject> receiver,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
StrictModeFlag strict_mode) {
|
||||
@ -480,7 +480,7 @@ Handle<Code> StubCache::ComputeStoreGlobal(Handle<String> name,
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeStoreCallback(
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<ExecutableAccessorInfo> callback,
|
||||
@ -500,7 +500,7 @@ Handle<Code> StubCache::ComputeStoreCallback(
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeStoreViaSetter(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeStoreViaSetter(Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> setter,
|
||||
@ -519,7 +519,7 @@ Handle<Code> StubCache::ComputeStoreViaSetter(Handle<String> name,
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> StubCache::ComputeStoreInterceptor(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeStoreInterceptor(Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
StrictModeFlag strict_mode) {
|
||||
Code::Flags flags = Code::ComputeMonomorphicFlags(
|
||||
@ -534,7 +534,7 @@ Handle<Code> StubCache::ComputeStoreInterceptor(Handle<String> name,
|
||||
return code;
|
||||
}
|
||||
|
||||
Handle<Code> StubCache::ComputeKeyedStoreField(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeKeyedStoreField(Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
int field_index,
|
||||
Handle<Map> transition,
|
||||
@ -562,7 +562,7 @@ Handle<Code> StubCache::ComputeKeyedStoreField(Handle<String> name,
|
||||
Handle<Code> StubCache::ComputeCallConstant(int argc,
|
||||
Code::Kind kind,
|
||||
Code::ExtraICState extra_state,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> function) {
|
||||
@ -614,7 +614,7 @@ Handle<Code> StubCache::ComputeCallConstant(int argc,
|
||||
Handle<Code> StubCache::ComputeCallField(int argc,
|
||||
Code::Kind kind,
|
||||
Code::ExtraICState extra_state,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
PropertyIndex index) {
|
||||
@ -654,7 +654,7 @@ Handle<Code> StubCache::ComputeCallField(int argc,
|
||||
Handle<Code> StubCache::ComputeCallInterceptor(int argc,
|
||||
Code::Kind kind,
|
||||
Code::ExtraICState extra_state,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<Object> object,
|
||||
Handle<JSObject> holder) {
|
||||
// Compute the check type and the map.
|
||||
@ -693,7 +693,7 @@ Handle<Code> StubCache::ComputeCallInterceptor(int argc,
|
||||
Handle<Code> StubCache::ComputeCallGlobal(int argc,
|
||||
Code::Kind kind,
|
||||
Code::ExtraICState extra_state,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<GlobalObject> holder,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
@ -893,7 +893,7 @@ Handle<Code> StubCache::ComputeLoadElementPolymorphic(
|
||||
|
||||
Handle<Code> StubCache::ComputePolymorphicIC(MapHandleList* receiver_maps,
|
||||
CodeHandleList* handlers,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
LoadStubCompiler ic_compiler(isolate_);
|
||||
Handle<Code> ic = ic_compiler.CompilePolymorphicIC(
|
||||
receiver_maps, handlers, name, Code::NORMAL, PROPERTY);
|
||||
@ -975,7 +975,7 @@ void StubCache::Clear() {
|
||||
|
||||
|
||||
void StubCache::CollectMatchingMaps(SmallMapList* types,
|
||||
String* name,
|
||||
Name* name,
|
||||
Code::Flags flags,
|
||||
Handle<Context> native_context,
|
||||
Zone* zone) {
|
||||
@ -1031,9 +1031,14 @@ RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
|
||||
v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
|
||||
ASSERT(fun != NULL);
|
||||
ASSERT(callback->IsCompatibleReceiver(recv));
|
||||
Handle<String> name = args.at<String>(2);
|
||||
Handle<Name> name = args.at<Name>(2);
|
||||
Handle<Object> value = args.at<Object>(3);
|
||||
HandleScope scope(isolate);
|
||||
|
||||
// TODO(rossberg): Support symbols in the API.
|
||||
if (name->IsSymbol()) return *value;
|
||||
Handle<String> str = Handle<String>::cast(name);
|
||||
|
||||
LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
|
||||
CustomArguments custom_args(isolate, callback->data(), recv, recv);
|
||||
v8::AccessorInfo info(custom_args.end());
|
||||
@ -1041,7 +1046,7 @@ RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
|
||||
// Leaving JavaScript.
|
||||
VMState state(isolate, EXTERNAL);
|
||||
ExternalCallbackScope call_scope(isolate, setter_address);
|
||||
fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
|
||||
fun(v8::Utils::ToLocal(str), v8::Utils::ToLocal(value), info);
|
||||
}
|
||||
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
|
||||
return *value;
|
||||
@ -1059,7 +1064,7 @@ static const int kAccessorInfoOffsetInInterceptorArgs = 2;
|
||||
* provide any value for the given name.
|
||||
*/
|
||||
RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
|
||||
Handle<String> name_handle = args.at<String>(0);
|
||||
Handle<Name> name_handle = args.at<Name>(0);
|
||||
Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
|
||||
ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
|
||||
ASSERT(args[2]->IsJSObject()); // Receiver.
|
||||
@ -1067,6 +1072,11 @@ RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
|
||||
ASSERT(args[5]->IsSmi()); // Isolate.
|
||||
ASSERT(args.length() == 6);
|
||||
|
||||
// TODO(rossberg): Support symbols in the API.
|
||||
if (name_handle->IsSymbol())
|
||||
return isolate->heap()->no_interceptor_result_sentinel();
|
||||
Handle<String> name = Handle<String>::cast(name_handle);
|
||||
|
||||
Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
|
||||
v8::NamedPropertyGetter getter =
|
||||
FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
|
||||
@ -1081,7 +1091,7 @@ RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
|
||||
{
|
||||
// Leaving JavaScript.
|
||||
VMState state(isolate, EXTERNAL);
|
||||
r = getter(v8::Utils::ToLocal(name_handle), info);
|
||||
r = getter(v8::Utils::ToLocal(name), info);
|
||||
}
|
||||
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
|
||||
if (!r.IsEmpty()) {
|
||||
@ -1095,7 +1105,7 @@ RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
|
||||
}
|
||||
|
||||
|
||||
static MaybeObject* ThrowReferenceError(Isolate* isolate, String* name) {
|
||||
static MaybeObject* ThrowReferenceError(Isolate* isolate, Name* name) {
|
||||
// If the load is non-contextual, just return the undefined result.
|
||||
// Note that both keyed and non-keyed loads may end up here, so we
|
||||
// can't use either LoadIC or KeyedLoadIC constructors.
|
||||
@ -1105,7 +1115,7 @@ static MaybeObject* ThrowReferenceError(Isolate* isolate, String* name) {
|
||||
|
||||
// Throw a reference error.
|
||||
HandleScope scope(isolate);
|
||||
Handle<String> name_handle(name);
|
||||
Handle<Name> name_handle(name);
|
||||
Handle<Object> error =
|
||||
FACTORY->NewReferenceError("not_defined",
|
||||
HandleVector(&name_handle, 1));
|
||||
@ -1115,7 +1125,7 @@ static MaybeObject* ThrowReferenceError(Isolate* isolate, String* name) {
|
||||
|
||||
static MaybeObject* LoadWithInterceptor(Arguments* args,
|
||||
PropertyAttributes* attrs) {
|
||||
Handle<String> name_handle = args->at<String>(0);
|
||||
Handle<Name> name_handle = args->at<Name>(0);
|
||||
Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
|
||||
ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
|
||||
Handle<JSObject> receiver_handle = args->at<JSObject>(2);
|
||||
@ -1124,6 +1134,12 @@ static MaybeObject* LoadWithInterceptor(Arguments* args,
|
||||
|
||||
Isolate* isolate = receiver_handle->GetIsolate();
|
||||
|
||||
// TODO(rossberg): Support symbols in the API.
|
||||
if (name_handle->IsSymbol())
|
||||
return holder_handle->GetPropertyPostInterceptor(
|
||||
*receiver_handle, *name_handle, attrs);
|
||||
Handle<String> name = Handle<String>::cast(name_handle);
|
||||
|
||||
Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
|
||||
v8::NamedPropertyGetter getter =
|
||||
FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
|
||||
@ -1138,7 +1154,7 @@ static MaybeObject* LoadWithInterceptor(Arguments* args,
|
||||
{
|
||||
// Leaving JavaScript.
|
||||
VMState state(isolate, EXTERNAL);
|
||||
r = getter(v8::Utils::ToLocal(name_handle), info);
|
||||
r = getter(v8::Utils::ToLocal(name), info);
|
||||
}
|
||||
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
|
||||
if (!r.IsEmpty()) {
|
||||
@ -1171,7 +1187,7 @@ RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
|
||||
|
||||
// If the property is present, return it.
|
||||
if (attr != ABSENT) return result;
|
||||
return ThrowReferenceError(isolate, String::cast(args[0]));
|
||||
return ThrowReferenceError(isolate, Name::cast(args[0]));
|
||||
}
|
||||
|
||||
|
||||
@ -1189,7 +1205,7 @@ RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
|
||||
RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
|
||||
ASSERT(args.length() == 4);
|
||||
JSObject* recv = JSObject::cast(args[0]);
|
||||
String* name = String::cast(args[1]);
|
||||
Name* name = Name::cast(args[1]);
|
||||
Object* value = args[2];
|
||||
ASSERT(args.smi_at(3) == kStrictMode || args.smi_at(3) == kNonStrictMode);
|
||||
StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
|
||||
@ -1371,15 +1387,15 @@ 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())
|
||||
Handle<Name> name) {
|
||||
return (FLAG_print_code_stubs && !name.is_null() && name->IsString())
|
||||
? GetCodeWithFlags(flags, *Handle<String>::cast(name)->ToCString())
|
||||
: GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
|
||||
}
|
||||
|
||||
|
||||
void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
LookupResult* lookup) {
|
||||
holder->LocalLookupRealNamedProperty(*name, lookup);
|
||||
if (lookup->IsFound()) return;
|
||||
@ -1394,7 +1410,7 @@ void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
|
||||
Register BaseLoadStubCompiler::HandlerFrontendHeader(Handle<JSObject> object,
|
||||
Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* miss) {
|
||||
// Check the prototype chain.
|
||||
return CheckPrototypes(object, object_reg, holder,
|
||||
@ -1406,7 +1422,7 @@ Register BaseLoadStubCompiler::HandlerFrontendHeader(Handle<JSObject> object,
|
||||
Register BaseLoadStubCompiler::HandlerFrontend(Handle<JSObject> object,
|
||||
Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* success) {
|
||||
Label miss;
|
||||
|
||||
@ -1419,7 +1435,7 @@ Register BaseLoadStubCompiler::HandlerFrontend(Handle<JSObject> object,
|
||||
|
||||
Handle<Code> BaseLoadStubCompiler::CompileLoadField(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
PropertyIndex field) {
|
||||
Label miss;
|
||||
|
||||
@ -1439,7 +1455,7 @@ Handle<Code> BaseLoadStubCompiler::CompileLoadField(Handle<JSObject> object,
|
||||
Handle<Code> BaseLoadStubCompiler::CompileLoadConstant(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSFunction> value) {
|
||||
Label success;
|
||||
HandlerFrontend(object, receiver(), holder, name, &success);
|
||||
@ -1454,7 +1470,7 @@ Handle<Code> BaseLoadStubCompiler::CompileLoadConstant(
|
||||
Handle<Code> BaseLoadStubCompiler::CompileLoadCallback(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
Label success;
|
||||
|
||||
@ -1471,7 +1487,7 @@ Handle<Code> BaseLoadStubCompiler::CompileLoadCallback(
|
||||
Handle<Code> BaseLoadStubCompiler::CompileLoadInterceptor(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
Label success;
|
||||
|
||||
LookupResult lookup(isolate());
|
||||
@ -1491,7 +1507,7 @@ Handle<Code> BaseLoadStubCompiler::CompileLoadInterceptor(
|
||||
void BaseLoadStubCompiler::GenerateLoadPostInterceptor(
|
||||
Register interceptor_reg,
|
||||
Handle<JSObject> interceptor_holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
LookupResult* lookup) {
|
||||
Label success;
|
||||
Handle<JSObject> holder(lookup->holder());
|
||||
@ -1529,7 +1545,7 @@ void BaseLoadStubCompiler::GenerateLoadPostInterceptor(
|
||||
Handle<Code> BaseLoadStubCompiler::CompileMonomorphicIC(
|
||||
Handle<Map> receiver_map,
|
||||
Handle<Code> handler,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
MapHandleList receiver_maps(1);
|
||||
receiver_maps.Add(receiver_map);
|
||||
CodeHandleList handlers(1);
|
||||
@ -1542,7 +1558,7 @@ Handle<Code> BaseLoadStubCompiler::CompileMonomorphicIC(
|
||||
Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSFunction> getter) {
|
||||
Label success;
|
||||
HandlerFrontend(object, receiver(), holder, name, &success);
|
||||
@ -1558,19 +1574,19 @@ Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
|
||||
#undef __
|
||||
|
||||
|
||||
void LoadStubCompiler::JitEvent(Handle<String> name, Handle<Code> code) {
|
||||
void LoadStubCompiler::JitEvent(Handle<Name> name, Handle<Code> code) {
|
||||
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
|
||||
}
|
||||
|
||||
|
||||
void KeyedLoadStubCompiler::JitEvent(Handle<String> name, Handle<Code> code) {
|
||||
void KeyedLoadStubCompiler::JitEvent(Handle<Name> name, Handle<Code> code) {
|
||||
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> BaseLoadStubCompiler::GetCode(Code::IcFragment fragment,
|
||||
Code::StubType type,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
InlineCacheState state) {
|
||||
Code::Flags flags = Code::ComputeFlags(kind(), state, fragment, type);
|
||||
Handle<Code> code = GetCodeWithFlags(flags, name);
|
||||
@ -1609,7 +1625,7 @@ void KeyedLoadStubCompiler::CompileElementHandlers(MapHandleList* receiver_maps,
|
||||
|
||||
|
||||
Handle<Code> StoreStubCompiler::GetCode(Code::StubType type,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
Code::Flags flags = Code::ComputeMonomorphicFlags(
|
||||
Code::STORE_IC, strict_mode_, type);
|
||||
Handle<Code> code = GetCodeWithFlags(flags, name);
|
||||
@ -1620,7 +1636,7 @@ Handle<Code> StoreStubCompiler::GetCode(Code::StubType type,
|
||||
|
||||
|
||||
Handle<Code> KeyedStoreStubCompiler::GetCode(Code::StubType type,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
InlineCacheState state) {
|
||||
Code::ExtraICState extra_state =
|
||||
Code::ComputeExtraICState(grow_mode_, strict_mode_);
|
||||
@ -1742,7 +1758,7 @@ Handle<Code> CallStubCompiler::CompileCustomCall(
|
||||
|
||||
|
||||
Handle<Code> CallStubCompiler::GetCode(Code::StubType type,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
int argc = arguments_.immediate();
|
||||
Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
|
||||
extra_state_,
|
||||
|
158
src/stub-cache.h
158
src/stub-cache.h
@ -67,7 +67,7 @@ class SCTableReference {
|
||||
class StubCache {
|
||||
public:
|
||||
struct Entry {
|
||||
String* key;
|
||||
Name* key;
|
||||
Code* value;
|
||||
Map* map;
|
||||
};
|
||||
@ -77,57 +77,57 @@ class StubCache {
|
||||
Handle<JSObject> StubHolder(Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder);
|
||||
|
||||
Handle<Code> FindStub(Handle<String> name,
|
||||
Handle<Code> FindStub(Handle<Name> name,
|
||||
Handle<JSObject> stub_holder,
|
||||
Code::Kind kind,
|
||||
Code::StubType type,
|
||||
Code::IcFragment fragment);
|
||||
|
||||
Handle<Code> FindHandler(Handle<String> name,
|
||||
Handle<Code> FindHandler(Handle<Name> name,
|
||||
Handle<JSObject> stub_holder,
|
||||
Code::Kind kind,
|
||||
Code::StubType type);
|
||||
|
||||
Handle<Code> ComputeMonomorphicIC(Handle<JSObject> receiver,
|
||||
Handle<Code> handler,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
Handle<Code> ComputeKeyedMonomorphicIC(Handle<JSObject> receiver,
|
||||
Handle<Code> handler,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
|
||||
// Computes the right stub matching. Inserts the result in the
|
||||
// cache before returning. This might compile a stub if needed.
|
||||
Handle<Code> ComputeLoadNonexistent(Handle<String> name,
|
||||
Handle<Code> ComputeLoadNonexistent(Handle<Name> name,
|
||||
Handle<JSObject> object);
|
||||
|
||||
Handle<Code> ComputeLoadField(Handle<String> name,
|
||||
Handle<Code> ComputeLoadField(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
PropertyIndex field_index);
|
||||
|
||||
Handle<Code> ComputeLoadCallback(Handle<String> name,
|
||||
Handle<Code> ComputeLoadCallback(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<ExecutableAccessorInfo> callback);
|
||||
|
||||
Handle<Code> ComputeLoadViaGetter(Handle<String> name,
|
||||
Handle<Code> ComputeLoadViaGetter(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> getter);
|
||||
|
||||
Handle<Code> ComputeLoadConstant(Handle<String> name,
|
||||
Handle<Code> ComputeLoadConstant(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> value);
|
||||
|
||||
Handle<Code> ComputeLoadInterceptor(Handle<String> name,
|
||||
Handle<Code> ComputeLoadInterceptor(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder);
|
||||
|
||||
Handle<Code> ComputeLoadNormal(Handle<String> name,
|
||||
Handle<Code> ComputeLoadNormal(Handle<Name> name,
|
||||
Handle<JSObject> object);
|
||||
|
||||
Handle<Code> ComputeLoadGlobal(Handle<String> name,
|
||||
Handle<Code> ComputeLoadGlobal(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<GlobalObject> holder,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
@ -135,29 +135,29 @@ class StubCache {
|
||||
|
||||
// ---
|
||||
|
||||
Handle<Code> ComputeKeyedLoadField(Handle<String> name,
|
||||
Handle<Code> ComputeKeyedLoadField(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
PropertyIndex field_index);
|
||||
|
||||
Handle<Code> ComputeKeyedLoadCallback(
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<ExecutableAccessorInfo> callback);
|
||||
|
||||
Handle<Code> ComputeKeyedLoadConstant(Handle<String> name,
|
||||
Handle<Code> ComputeKeyedLoadConstant(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> value);
|
||||
|
||||
Handle<Code> ComputeKeyedLoadInterceptor(Handle<String> name,
|
||||
Handle<Code> ComputeKeyedLoadInterceptor(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder);
|
||||
|
||||
// ---
|
||||
|
||||
Handle<Code> ComputeStoreField(Handle<String> name,
|
||||
Handle<Code> ComputeStoreField(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
int field_index,
|
||||
Handle<Map> transition,
|
||||
@ -165,30 +165,30 @@ class StubCache {
|
||||
|
||||
Handle<Code> ComputeStoreNormal(StrictModeFlag strict_mode);
|
||||
|
||||
Handle<Code> ComputeStoreGlobal(Handle<String> name,
|
||||
Handle<Code> ComputeStoreGlobal(Handle<Name> name,
|
||||
Handle<GlobalObject> object,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
StrictModeFlag strict_mode);
|
||||
|
||||
Handle<Code> ComputeStoreCallback(Handle<String> name,
|
||||
Handle<Code> ComputeStoreCallback(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<ExecutableAccessorInfo> callback,
|
||||
StrictModeFlag strict_mode);
|
||||
|
||||
Handle<Code> ComputeStoreViaSetter(Handle<String> name,
|
||||
Handle<Code> ComputeStoreViaSetter(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> setter,
|
||||
StrictModeFlag strict_mode);
|
||||
|
||||
Handle<Code> ComputeStoreInterceptor(Handle<String> name,
|
||||
Handle<Code> ComputeStoreInterceptor(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
StrictModeFlag strict_mode);
|
||||
|
||||
// ---
|
||||
|
||||
Handle<Code> ComputeKeyedStoreField(Handle<String> name,
|
||||
Handle<Code> ComputeKeyedStoreField(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
int field_index,
|
||||
Handle<Map> transition,
|
||||
@ -206,7 +206,7 @@ class StubCache {
|
||||
Handle<Code> ComputeCallField(int argc,
|
||||
Code::Kind,
|
||||
Code::ExtraICState extra_state,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
PropertyIndex index);
|
||||
@ -214,7 +214,7 @@ class StubCache {
|
||||
Handle<Code> ComputeCallConstant(int argc,
|
||||
Code::Kind,
|
||||
Code::ExtraICState extra_state,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> function);
|
||||
@ -222,14 +222,14 @@ class StubCache {
|
||||
Handle<Code> ComputeCallInterceptor(int argc,
|
||||
Code::Kind,
|
||||
Code::ExtraICState extra_state,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<Object> object,
|
||||
Handle<JSObject> holder);
|
||||
|
||||
Handle<Code> ComputeCallGlobal(int argc,
|
||||
Code::Kind,
|
||||
Code::ExtraICState extra_state,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<GlobalObject> holder,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
@ -268,7 +268,7 @@ class StubCache {
|
||||
|
||||
Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
|
||||
CodeHandleList* handlers,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
|
||||
// Finds the Code object stored in the Heap::non_monomorphic_cache().
|
||||
Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind);
|
||||
@ -280,14 +280,14 @@ class StubCache {
|
||||
#endif
|
||||
|
||||
// Update cache for entry hash(name, map).
|
||||
Code* Set(String* name, Map* map, Code* code);
|
||||
Code* Set(Name* name, Map* map, Code* code);
|
||||
|
||||
// Clear the lookup table (@ mark compact collection).
|
||||
void Clear();
|
||||
|
||||
// Collect all maps that match the name and flags.
|
||||
void CollectMatchingMaps(SmallMapList* types,
|
||||
String* name,
|
||||
Name* name,
|
||||
Code::Flags flags,
|
||||
Handle<Context> native_context,
|
||||
Zone* zone);
|
||||
@ -358,12 +358,12 @@ class StubCache {
|
||||
// Hash algorithm for the primary table. This algorithm is replicated in
|
||||
// assembler for every architecture. Returns an index into the table that
|
||||
// is scaled by 1 << kHeapObjectTagSize.
|
||||
static int PrimaryOffset(String* name, Code::Flags flags, Map* map) {
|
||||
static int PrimaryOffset(Name* name, Code::Flags flags, Map* map) {
|
||||
// This works well because the heap object tag size and the hash
|
||||
// shift are equal. Shifting down the length field to get the
|
||||
// hash code would effectively throw away two bits of the hash
|
||||
// code.
|
||||
STATIC_ASSERT(kHeapObjectTagSize == String::kHashShift);
|
||||
STATIC_ASSERT(kHeapObjectTagSize == Name::kHashShift);
|
||||
// Compute the hash of the name (use entire hash field).
|
||||
ASSERT(name->HasHashCode());
|
||||
uint32_t field = name->hash_field();
|
||||
@ -384,25 +384,25 @@ class StubCache {
|
||||
// Hash algorithm for the secondary table. This algorithm is replicated in
|
||||
// assembler for every architecture. Returns an index into the table that
|
||||
// is scaled by 1 << kHeapObjectTagSize.
|
||||
static int SecondaryOffset(String* name, Code::Flags flags, int seed) {
|
||||
static int SecondaryOffset(Name* name, Code::Flags flags, int seed) {
|
||||
// Use the seed from the primary cache in the secondary cache.
|
||||
uint32_t string_low32bits =
|
||||
uint32_t name_low32bits =
|
||||
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name));
|
||||
// We always set the in_loop bit to zero when generating the lookup code
|
||||
// so do it here too so the hash codes match.
|
||||
uint32_t iflags =
|
||||
(static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
|
||||
uint32_t key = (seed - string_low32bits) + iflags;
|
||||
uint32_t key = (seed - name_low32bits) + iflags;
|
||||
return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize);
|
||||
}
|
||||
|
||||
// Compute the entry for a given offset in exactly the same way as
|
||||
// we do in generated code. We generate an hash code that already
|
||||
// ends in String::kHashShift 0s. Then we multiply it so it is a multiple
|
||||
// ends in Name::kHashShift 0s. Then we multiply it so it is a multiple
|
||||
// of sizeof(Entry). This makes it easier to avoid making mistakes
|
||||
// in the hashed offset computations.
|
||||
static Entry* entry(Entry* table, int offset) {
|
||||
const int multiplier = sizeof(*table) >> String::kHashShift;
|
||||
const int multiplier = sizeof(*table) >> Name::kHashShift;
|
||||
return reinterpret_cast<Entry*>(
|
||||
reinterpret_cast<Address>(table) + offset * multiplier);
|
||||
}
|
||||
@ -512,7 +512,7 @@ class StubCompiler BASE_EMBEDDED {
|
||||
Handle<JSObject> object,
|
||||
int index,
|
||||
Handle<Map> transition,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register receiver_reg,
|
||||
Register name_reg,
|
||||
Register scratch1,
|
||||
@ -545,7 +545,7 @@ class StubCompiler BASE_EMBEDDED {
|
||||
Register holder_reg,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* miss,
|
||||
PrototypeCheckType check = CHECK_ALL_MAPS) {
|
||||
return CheckPrototypes(object, object_reg, holder, holder_reg, scratch1,
|
||||
@ -558,7 +558,7 @@ class StubCompiler BASE_EMBEDDED {
|
||||
Register holder_reg,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
int save_at_depth,
|
||||
Label* miss,
|
||||
PrototypeCheckType check = CHECK_ALL_MAPS);
|
||||
@ -566,13 +566,13 @@ class StubCompiler BASE_EMBEDDED {
|
||||
|
||||
protected:
|
||||
Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
|
||||
Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<String> name);
|
||||
Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name);
|
||||
|
||||
MacroAssembler* masm() { return &masm_; }
|
||||
void set_failure(Failure* failure) { failure_ = failure; }
|
||||
|
||||
static void LookupPostInterceptor(Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
LookupResult* lookup);
|
||||
|
||||
Isolate* isolate() { return isolate_; }
|
||||
@ -599,29 +599,29 @@ class BaseLoadStubCompiler: public StubCompiler {
|
||||
|
||||
Handle<Code> CompileLoadField(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
PropertyIndex index);
|
||||
|
||||
Handle<Code> CompileLoadCallback(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<ExecutableAccessorInfo> callback);
|
||||
|
||||
Handle<Code> CompileLoadConstant(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSFunction> value);
|
||||
|
||||
Handle<Code> CompileLoadInterceptor(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
|
||||
Handle<Code> CompileMonomorphicIC(Handle<Map> receiver_map,
|
||||
Handle<Code> handler,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
Handle<Code> CompilePolymorphicIC(MapHandleList* receiver_maps,
|
||||
CodeHandleList* handlers,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Code::StubType type,
|
||||
IcCheckType check);
|
||||
|
||||
@ -629,24 +629,24 @@ class BaseLoadStubCompiler: public StubCompiler {
|
||||
Register HandlerFrontendHeader(Handle<JSObject> object,
|
||||
Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* success);
|
||||
void HandlerFrontendFooter(Label* success, Label* miss);
|
||||
|
||||
Register HandlerFrontend(Handle<JSObject> object,
|
||||
Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* success);
|
||||
Register CallbackHandlerFrontend(Handle<JSObject> object,
|
||||
Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* success,
|
||||
Handle<ExecutableAccessorInfo> callback);
|
||||
void NonexistentHandlerFrontend(Handle<JSObject> object,
|
||||
Handle<JSObject> last,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* success,
|
||||
Handle<GlobalObject> global);
|
||||
|
||||
@ -660,15 +660,15 @@ class BaseLoadStubCompiler: public StubCompiler {
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
LookupResult* lookup,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
void GenerateLoadPostInterceptor(Register reg,
|
||||
Handle<JSObject> interceptor_holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
LookupResult* lookup);
|
||||
|
||||
Handle<Code> GetCode(Code::IcFragment fragment,
|
||||
Code::StubType type,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
InlineCacheState state = MONOMORPHIC);
|
||||
|
||||
Register receiver() { return registers_[0]; }
|
||||
@ -681,8 +681,8 @@ class BaseLoadStubCompiler: public StubCompiler {
|
||||
private:
|
||||
virtual Code::Kind kind() = 0;
|
||||
virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) = 0;
|
||||
virtual void JitEvent(Handle<String> name, Handle<Code> code) = 0;
|
||||
virtual void GenerateNameCheck(Handle<String> name,
|
||||
virtual void JitEvent(Handle<Name> name, Handle<Code> code) = 0;
|
||||
virtual void GenerateNameCheck(Handle<Name> name,
|
||||
Register name_reg,
|
||||
Label* miss) { }
|
||||
Register* registers_;
|
||||
@ -696,7 +696,7 @@ class LoadStubCompiler: public BaseLoadStubCompiler {
|
||||
|
||||
Handle<Code> CompileLoadNonexistent(Handle<JSObject> object,
|
||||
Handle<JSObject> last,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<GlobalObject> global);
|
||||
|
||||
static void GenerateLoadViaGetter(MacroAssembler* masm,
|
||||
@ -704,13 +704,13 @@ class LoadStubCompiler: public BaseLoadStubCompiler {
|
||||
|
||||
Handle<Code> CompileLoadViaGetter(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSFunction> getter);
|
||||
|
||||
Handle<Code> CompileLoadGlobal(Handle<JSObject> object,
|
||||
Handle<GlobalObject> holder,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
bool is_dont_delete);
|
||||
|
||||
static Register receiver() { return registers()[0]; }
|
||||
@ -722,7 +722,7 @@ class LoadStubCompiler: public BaseLoadStubCompiler {
|
||||
return code->ic_state() == MONOMORPHIC
|
||||
? Logger::LOAD_IC_TAG : Logger::LOAD_POLYMORPHIC_IC_TAG;
|
||||
}
|
||||
virtual void JitEvent(Handle<String> name, Handle<Code> code);
|
||||
virtual void JitEvent(Handle<Name> name, Handle<Code> code);
|
||||
};
|
||||
|
||||
|
||||
@ -749,8 +749,8 @@ class KeyedLoadStubCompiler: public BaseLoadStubCompiler {
|
||||
return code->ic_state() == MONOMORPHIC
|
||||
? Logger::KEYED_LOAD_IC_TAG : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG;
|
||||
}
|
||||
virtual void JitEvent(Handle<String> name, Handle<Code> code);
|
||||
virtual void GenerateNameCheck(Handle<String> name,
|
||||
virtual void JitEvent(Handle<Name> name, Handle<Code> code);
|
||||
virtual void GenerateNameCheck(Handle<Name> name,
|
||||
Register name_reg,
|
||||
Label* miss);
|
||||
};
|
||||
@ -765,9 +765,9 @@ class StoreStubCompiler: public StubCompiler {
|
||||
Handle<Code> CompileStoreField(Handle<JSObject> object,
|
||||
int index,
|
||||
Handle<Map> transition,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
|
||||
Handle<Code> CompileStoreCallback(Handle<String> name,
|
||||
Handle<Code> CompileStoreCallback(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<ExecutableAccessorInfo> callback);
|
||||
@ -775,20 +775,20 @@ class StoreStubCompiler: public StubCompiler {
|
||||
static void GenerateStoreViaSetter(MacroAssembler* masm,
|
||||
Handle<JSFunction> setter);
|
||||
|
||||
Handle<Code> CompileStoreViaSetter(Handle<String> name,
|
||||
Handle<Code> CompileStoreViaSetter(Handle<Name> name,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> setter);
|
||||
|
||||
Handle<Code> CompileStoreInterceptor(Handle<JSObject> object,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
|
||||
Handle<Code> CompileStoreGlobal(Handle<GlobalObject> object,
|
||||
Handle<JSGlobalPropertyCell> holder,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
|
||||
private:
|
||||
Handle<Code> GetCode(Code::StubType type, Handle<String> name);
|
||||
Handle<Code> GetCode(Code::StubType type, Handle<Name> name);
|
||||
|
||||
StrictModeFlag strict_mode_;
|
||||
};
|
||||
@ -806,7 +806,7 @@ class KeyedStoreStubCompiler: public StubCompiler {
|
||||
Handle<Code> CompileStoreField(Handle<JSObject> object,
|
||||
int index,
|
||||
Handle<Map> transition,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
|
||||
Handle<Code> CompileStoreElement(Handle<Map> receiver_map);
|
||||
|
||||
@ -832,7 +832,7 @@ class KeyedStoreStubCompiler: public StubCompiler {
|
||||
|
||||
private:
|
||||
Handle<Code> GetCode(Code::StubType type,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
InlineCacheState state = MONOMORPHIC);
|
||||
|
||||
StrictModeFlag strict_mode_;
|
||||
@ -865,11 +865,11 @@ class CallStubCompiler: public StubCompiler {
|
||||
Handle<Code> CompileCallField(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
PropertyIndex index,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
|
||||
void CompileHandlerFrontend(Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
CheckType check,
|
||||
Label* success);
|
||||
|
||||
@ -877,19 +877,19 @@ class CallStubCompiler: public StubCompiler {
|
||||
|
||||
Handle<Code> CompileCallConstant(Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
CheckType check,
|
||||
Handle<JSFunction> function);
|
||||
|
||||
Handle<Code> CompileCallInterceptor(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
|
||||
Handle<Code> CompileCallGlobal(Handle<JSObject> object,
|
||||
Handle<GlobalObject> holder,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
Handle<JSFunction> function,
|
||||
Handle<String> name);
|
||||
Handle<Name> name);
|
||||
|
||||
static bool HasCustomCallGenerator(Handle<JSFunction> function);
|
||||
|
||||
@ -919,16 +919,16 @@ class CallStubCompiler: public StubCompiler {
|
||||
Handle<JSFunction> function,
|
||||
Handle<String> name);
|
||||
|
||||
Handle<Code> GetCode(Code::StubType type, Handle<String> name);
|
||||
Handle<Code> GetCode(Code::StubType type, Handle<Name> name);
|
||||
Handle<Code> GetCode(Handle<JSFunction> function);
|
||||
|
||||
const ParameterCount& arguments() { return arguments_; }
|
||||
|
||||
void GenerateNameCheck(Handle<String> name, Label* miss);
|
||||
void GenerateNameCheck(Handle<Name> name, Label* miss);
|
||||
|
||||
void GenerateGlobalReceiverCheck(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* miss);
|
||||
|
||||
// Generates code to load the function from the cell checking that
|
||||
|
@ -143,19 +143,19 @@ Object** TransitionArray::GetKeySlot(int transition_number) {
|
||||
}
|
||||
|
||||
|
||||
String* TransitionArray::GetKey(int transition_number) {
|
||||
Name* TransitionArray::GetKey(int transition_number) {
|
||||
if (IsSimpleTransition()) {
|
||||
Map* target = GetTarget(kSimpleTransitionIndex);
|
||||
int descriptor = target->LastAdded();
|
||||
String* key = target->instance_descriptors()->GetKey(descriptor);
|
||||
Name* key = target->instance_descriptors()->GetKey(descriptor);
|
||||
return key;
|
||||
}
|
||||
ASSERT(transition_number < number_of_transitions());
|
||||
return String::cast(get(ToKeyIndex(transition_number)));
|
||||
return Name::cast(get(ToKeyIndex(transition_number)));
|
||||
}
|
||||
|
||||
|
||||
void TransitionArray::SetKey(int transition_number, String* key) {
|
||||
void TransitionArray::SetKey(int transition_number, Name* key) {
|
||||
ASSERT(!IsSimpleTransition());
|
||||
ASSERT(transition_number < number_of_transitions());
|
||||
set(ToKeyIndex(transition_number), key);
|
||||
@ -190,9 +190,9 @@ PropertyDetails TransitionArray::GetTargetDetails(int transition_number) {
|
||||
}
|
||||
|
||||
|
||||
int TransitionArray::Search(String* name) {
|
||||
int TransitionArray::Search(Name* name) {
|
||||
if (IsSimpleTransition()) {
|
||||
String* key = GetKey(kSimpleTransitionIndex);
|
||||
Name* key = GetKey(kSimpleTransitionIndex);
|
||||
if (key->Equals(name)) return kSimpleTransitionIndex;
|
||||
return kNotFound;
|
||||
}
|
||||
@ -201,7 +201,7 @@ int TransitionArray::Search(String* name) {
|
||||
|
||||
|
||||
void TransitionArray::NoIncrementalWriteBarrierSet(int transition_number,
|
||||
String* key,
|
||||
Name* key,
|
||||
Map* target) {
|
||||
FixedArray::NoIncrementalWriteBarrierSet(
|
||||
this, ToKeyIndex(transition_number), key);
|
||||
|
@ -65,13 +65,13 @@ void TransitionArray::NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin,
|
||||
}
|
||||
|
||||
|
||||
static bool InsertionPointFound(String* key1, String* key2) {
|
||||
static bool InsertionPointFound(Name* key1, Name* key2) {
|
||||
return key1->Hash() > key2->Hash();
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* TransitionArray::NewWith(SimpleTransitionFlag flag,
|
||||
String* key,
|
||||
Name* key,
|
||||
Map* target,
|
||||
Object* back_pointer) {
|
||||
TransitionArray* result;
|
||||
@ -107,7 +107,7 @@ MaybeObject* TransitionArray::ExtendToFullTransitionArray() {
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* TransitionArray::CopyInsert(String* name, Map* target) {
|
||||
MaybeObject* TransitionArray::CopyInsert(Name* name, Map* target) {
|
||||
TransitionArray* result;
|
||||
|
||||
int number_of_transitions = this->number_of_transitions();
|
||||
|
@ -59,12 +59,12 @@ namespace internal {
|
||||
class TransitionArray: public FixedArray {
|
||||
public:
|
||||
// Accessors for fetching instance transition at transition number.
|
||||
inline String* GetKey(int transition_number);
|
||||
inline void SetKey(int transition_number, String* value);
|
||||
inline Name* GetKey(int transition_number);
|
||||
inline void SetKey(int transition_number, Name* value);
|
||||
inline Object** GetKeySlot(int transition_number);
|
||||
int GetSortedKeyIndex(int transition_number) { return transition_number; }
|
||||
|
||||
String* GetSortedKey(int transition_number) {
|
||||
Name* GetSortedKey(int transition_number) {
|
||||
return GetKey(transition_number);
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ class TransitionArray: public FixedArray {
|
||||
// Allocate a new transition array with a single entry.
|
||||
static MUST_USE_RESULT MaybeObject* NewWith(
|
||||
SimpleTransitionFlag flag,
|
||||
String* key,
|
||||
Name* key,
|
||||
Map* target,
|
||||
Object* back_pointer);
|
||||
|
||||
@ -114,7 +114,7 @@ class TransitionArray: public FixedArray {
|
||||
// Copy the transition array, inserting a new transition.
|
||||
// TODO(verwaest): This should not cause an existing transition to be
|
||||
// overwritten.
|
||||
MUST_USE_RESULT MaybeObject* CopyInsert(String* name, Map* target);
|
||||
MUST_USE_RESULT MaybeObject* CopyInsert(Name* name, Map* target);
|
||||
|
||||
// Copy a single transition from the origin array.
|
||||
inline void NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin,
|
||||
@ -122,7 +122,7 @@ class TransitionArray: public FixedArray {
|
||||
int target_transition);
|
||||
|
||||
// Search a transition for a given property name.
|
||||
inline int Search(String* name);
|
||||
inline int Search(Name* name);
|
||||
|
||||
// Allocates a TransitionArray.
|
||||
MUST_USE_RESULT static MaybeObject* Allocate(int number_of_transitions);
|
||||
@ -195,7 +195,7 @@ class TransitionArray: public FixedArray {
|
||||
}
|
||||
|
||||
inline void NoIncrementalWriteBarrierSet(int transition_number,
|
||||
String* key,
|
||||
Name* key,
|
||||
Map* target);
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(TransitionArray);
|
||||
|
@ -128,12 +128,13 @@ class FunctionTemplateInfo;
|
||||
class MemoryChunk;
|
||||
class SeededNumberDictionary;
|
||||
class UnseededNumberDictionary;
|
||||
class StringDictionary;
|
||||
class NameDictionary;
|
||||
template <typename T> class Handle;
|
||||
class Heap;
|
||||
class HeapObject;
|
||||
class IC;
|
||||
class InterceptorInfo;
|
||||
class JSReceiver;
|
||||
class JSArray;
|
||||
class JSFunction;
|
||||
class JSObject;
|
||||
@ -155,6 +156,7 @@ class Smi;
|
||||
template <typename Config, class Allocator = FreeStoreAllocationPolicy>
|
||||
class SplayTree;
|
||||
class String;
|
||||
class Name;
|
||||
class Struct;
|
||||
class Variable;
|
||||
class RelocInfo;
|
||||
|
@ -258,9 +258,9 @@ function ObjectValueOf() {
|
||||
function ObjectHasOwnProperty(V) {
|
||||
if (%IsJSProxy(this)) {
|
||||
var handler = %GetHandler(this);
|
||||
return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, TO_STRING_INLINE(V));
|
||||
return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V));
|
||||
}
|
||||
return %HasLocalProperty(TO_OBJECT_INLINE(this), TO_STRING_INLINE(V));
|
||||
return %HasLocalProperty(TO_OBJECT_INLINE(this), ToName(V));
|
||||
}
|
||||
|
||||
|
||||
@ -277,7 +277,7 @@ function ObjectIsPrototypeOf(V) {
|
||||
|
||||
// ECMA-262 - 15.2.4.6
|
||||
function ObjectPropertyIsEnumerable(V) {
|
||||
var P = ToString(V);
|
||||
var P = ToName(V);
|
||||
if (%IsJSProxy(this)) {
|
||||
var desc = GetOwnProperty(this, P);
|
||||
return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
|
||||
@ -300,7 +300,7 @@ function ObjectDefineGetter(name, fun) {
|
||||
desc.setGet(fun);
|
||||
desc.setEnumerable(true);
|
||||
desc.setConfigurable(true);
|
||||
DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
|
||||
DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
|
||||
}
|
||||
|
||||
|
||||
@ -309,7 +309,7 @@ function ObjectLookupGetter(name) {
|
||||
if (receiver == null && !IS_UNDETECTABLE(receiver)) {
|
||||
receiver = %GlobalReceiver(global);
|
||||
}
|
||||
return %LookupAccessor(ToObject(receiver), ToString(name), GETTER);
|
||||
return %LookupAccessor(ToObject(receiver), ToName(name), GETTER);
|
||||
}
|
||||
|
||||
|
||||
@ -326,7 +326,7 @@ function ObjectDefineSetter(name, fun) {
|
||||
desc.setSet(fun);
|
||||
desc.setEnumerable(true);
|
||||
desc.setConfigurable(true);
|
||||
DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
|
||||
DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
|
||||
}
|
||||
|
||||
|
||||
@ -335,7 +335,7 @@ function ObjectLookupSetter(name) {
|
||||
if (receiver == null && !IS_UNDETECTABLE(receiver)) {
|
||||
receiver = %GlobalReceiver(global);
|
||||
}
|
||||
return %LookupAccessor(ToObject(receiver), ToString(name), SETTER);
|
||||
return %LookupAccessor(ToObject(receiver), ToName(name), SETTER);
|
||||
}
|
||||
|
||||
|
||||
@ -346,7 +346,8 @@ function ObjectKeys(obj) {
|
||||
if (%IsJSProxy(obj)) {
|
||||
var handler = %GetHandler(obj);
|
||||
var names = CallTrap0(handler, "keys", DerivedKeysTrap);
|
||||
return ToStringArray(names, "keys");
|
||||
// TODO(rossberg): filter non-string keys.
|
||||
return ToNameArray(names, "keys");
|
||||
}
|
||||
return %LocalKeys(obj);
|
||||
}
|
||||
@ -644,7 +645,7 @@ function CallTrap2(handler, name, defaultTrap, x, y) {
|
||||
|
||||
// ES5 section 8.12.1.
|
||||
function GetOwnProperty(obj, v) {
|
||||
var p = ToString(v);
|
||||
var p = ToName(v);
|
||||
if (%IsJSProxy(obj)) {
|
||||
var handler = %GetHandler(obj);
|
||||
var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
|
||||
@ -660,7 +661,7 @@ function GetOwnProperty(obj, v) {
|
||||
// GetOwnProperty returns an array indexed by the constants
|
||||
// defined in macros.py.
|
||||
// If p is not a property on obj undefined is returned.
|
||||
var props = %GetOwnProperty(ToObject(obj), ToString(v));
|
||||
var props = %GetOwnProperty(ToObject(obj), p);
|
||||
|
||||
// A false value here means that access checks failed.
|
||||
if (props === false) return void 0;
|
||||
@ -702,7 +703,7 @@ function DefineProxyProperty(obj, p, attributes, should_throw) {
|
||||
|
||||
// ES5 8.12.9.
|
||||
function DefineObjectProperty(obj, p, desc, should_throw) {
|
||||
var current_or_access = %GetOwnProperty(ToObject(obj), ToString(p));
|
||||
var current_or_access = %GetOwnProperty(ToObject(obj), ToName(p));
|
||||
// A false value here means that access checks failed.
|
||||
if (current_or_access === false) return void 0;
|
||||
|
||||
@ -982,7 +983,7 @@ function ObjectGetOwnPropertyDescriptor(obj, p) {
|
||||
|
||||
|
||||
// For Harmony proxies
|
||||
function ToStringArray(obj, trap) {
|
||||
function ToNameArray(obj, trap) {
|
||||
if (!IS_SPEC_OBJECT(obj)) {
|
||||
throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
|
||||
}
|
||||
@ -990,7 +991,7 @@ function ToStringArray(obj, trap) {
|
||||
var array = new $Array(n);
|
||||
var names = { __proto__: null }; // TODO(rossberg): use sets once ready.
|
||||
for (var index = 0; index < n; index++) {
|
||||
var s = ToString(obj[index]);
|
||||
var s = ToName(obj[index]);
|
||||
if (%HasLocalProperty(names, s)) {
|
||||
throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
|
||||
}
|
||||
@ -1010,7 +1011,7 @@ function ObjectGetOwnPropertyNames(obj) {
|
||||
if (%IsJSProxy(obj)) {
|
||||
var handler = %GetHandler(obj);
|
||||
var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
|
||||
return ToStringArray(names, "getOwnPropertyNames");
|
||||
return ToNameArray(names, "getOwnPropertyNames");
|
||||
}
|
||||
|
||||
// Find all the indexed properties.
|
||||
@ -1045,13 +1046,13 @@ function ObjectGetOwnPropertyNames(obj) {
|
||||
}
|
||||
}
|
||||
|
||||
// Property names are expected to be unique strings,
|
||||
// Property names are expected to be unique names,
|
||||
// but interceptors can interfere with that assumption.
|
||||
if (interceptorInfo != 0) {
|
||||
var propertySet = { __proto__: null };
|
||||
var j = 0;
|
||||
for (var i = 0; i < propertyNames.length; ++i) {
|
||||
var name = ToString(propertyNames[i]);
|
||||
var name = ToName(propertyNames[i]);
|
||||
// We need to check for the exact property value since for intrinsic
|
||||
// properties like toString if(propertySet["toString"]) will always
|
||||
// succeed.
|
||||
@ -1085,7 +1086,7 @@ function ObjectDefineProperty(obj, p, attributes) {
|
||||
if (!IS_SPEC_OBJECT(obj)) {
|
||||
throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
|
||||
}
|
||||
var name = ToString(p);
|
||||
var name = ToName(p);
|
||||
if (%IsJSProxy(obj)) {
|
||||
// Clone the attributes object for protection.
|
||||
// TODO(rossberg): not spec'ed yet, so not sure if this should involve
|
||||
|
@ -6210,12 +6210,13 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register properties,
|
||||
Handle<String> name,
|
||||
Register r0) {
|
||||
void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register properties,
|
||||
Handle<Name> name,
|
||||
Register r0) {
|
||||
ASSERT(name->IsUniqueName());
|
||||
// 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
|
||||
@ -6229,10 +6230,10 @@ void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
__ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset));
|
||||
__ decl(index);
|
||||
__ and_(index,
|
||||
Immediate(name->Hash() + StringDictionary::GetProbeOffset(i)));
|
||||
Immediate(name->Hash() + NameDictionary::GetProbeOffset(i)));
|
||||
|
||||
// Scale the index by multiplying by the entry size.
|
||||
ASSERT(StringDictionary::kEntrySize == 3);
|
||||
ASSERT(NameDictionary::kEntrySize == 3);
|
||||
__ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
|
||||
|
||||
Register entity_name = r0;
|
||||
@ -6246,27 +6247,27 @@ void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
__ j(equal, done);
|
||||
|
||||
// Stop if found the property.
|
||||
__ Cmp(entity_name, Handle<String>(name));
|
||||
__ Cmp(entity_name, Handle<Name>(name));
|
||||
__ j(equal, miss);
|
||||
|
||||
Label the_hole;
|
||||
Label good;
|
||||
// Check for the hole and skip.
|
||||
__ CompareRoot(entity_name, Heap::kTheHoleValueRootIndex);
|
||||
__ j(equal, &the_hole, Label::kNear);
|
||||
__ j(equal, &good, Label::kNear);
|
||||
|
||||
// Check if the entry name is not an internalized string.
|
||||
// Check if the entry name is not a unique name.
|
||||
__ movq(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
|
||||
__ testb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
|
||||
Immediate(kIsInternalizedMask));
|
||||
__ j(zero, miss);
|
||||
__ j(not_zero, &good, Label::kNear);
|
||||
__ cmpb(FieldOperand(entity_name, Map::kInstanceTypeOffset),
|
||||
Immediate(static_cast<int8_t>(SYMBOL_TYPE)));
|
||||
__ j(not_equal, miss);
|
||||
|
||||
__ bind(&the_hole);
|
||||
__ bind(&good);
|
||||
}
|
||||
|
||||
StringDictionaryLookupStub stub(properties,
|
||||
r0,
|
||||
r0,
|
||||
StringDictionaryLookupStub::NEGATIVE_LOOKUP);
|
||||
NameDictionaryLookupStub stub(properties, r0, r0, NEGATIVE_LOOKUP);
|
||||
__ Push(Handle<Object>(name));
|
||||
__ push(Immediate(name->Hash()));
|
||||
__ CallStub(&stub);
|
||||
@ -6276,38 +6277,38 @@ void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Probe the string dictionary in the |elements| register. Jump to the
|
||||
// Probe the name dictionary in the |elements| register. Jump to the
|
||||
// |done| label if a property with the given name is found leaving the
|
||||
// index into the dictionary in |r1|. Jump to the |miss| label
|
||||
// otherwise.
|
||||
void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register elements,
|
||||
Register name,
|
||||
Register r0,
|
||||
Register r1) {
|
||||
void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register elements,
|
||||
Register name,
|
||||
Register r0,
|
||||
Register r1) {
|
||||
ASSERT(!elements.is(r0));
|
||||
ASSERT(!elements.is(r1));
|
||||
ASSERT(!name.is(r0));
|
||||
ASSERT(!name.is(r1));
|
||||
|
||||
__ AssertString(name);
|
||||
__ AssertName(name);
|
||||
|
||||
__ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset));
|
||||
__ decl(r0);
|
||||
|
||||
for (int i = 0; i < kInlinedProbes; i++) {
|
||||
// Compute the masked index: (hash + i + i * i) & mask.
|
||||
__ movl(r1, FieldOperand(name, String::kHashFieldOffset));
|
||||
__ shrl(r1, Immediate(String::kHashShift));
|
||||
__ movl(r1, FieldOperand(name, Name::kHashFieldOffset));
|
||||
__ shrl(r1, Immediate(Name::kHashShift));
|
||||
if (i > 0) {
|
||||
__ addl(r1, Immediate(StringDictionary::GetProbeOffset(i)));
|
||||
__ addl(r1, Immediate(NameDictionary::GetProbeOffset(i)));
|
||||
}
|
||||
__ and_(r1, r0);
|
||||
|
||||
// Scale the index by multiplying by the entry size.
|
||||
ASSERT(StringDictionary::kEntrySize == 3);
|
||||
ASSERT(NameDictionary::kEntrySize == 3);
|
||||
__ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3
|
||||
|
||||
// Check if the key is identical to the name.
|
||||
@ -6316,13 +6317,10 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
__ j(equal, done);
|
||||
}
|
||||
|
||||
StringDictionaryLookupStub stub(elements,
|
||||
r0,
|
||||
r1,
|
||||
POSITIVE_LOOKUP);
|
||||
NameDictionaryLookupStub stub(elements, r0, r1, POSITIVE_LOOKUP);
|
||||
__ push(name);
|
||||
__ movl(r0, FieldOperand(name, String::kHashFieldOffset));
|
||||
__ shrl(r0, Immediate(String::kHashShift));
|
||||
__ movl(r0, FieldOperand(name, Name::kHashFieldOffset));
|
||||
__ shrl(r0, Immediate(Name::kHashShift));
|
||||
__ push(r0);
|
||||
__ CallStub(&stub);
|
||||
|
||||
@ -6332,7 +6330,7 @@ void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
// This stub overrides SometimesSetsUpAFrame() to return false. That means
|
||||
// we cannot call anything that could cause a GC from this stub.
|
||||
// Stack frame on entry:
|
||||
@ -6340,7 +6338,7 @@ void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
// esp[1 * kPointerSize]: key's hash.
|
||||
// esp[2 * kPointerSize]: key.
|
||||
// Registers:
|
||||
// dictionary_: StringDictionary to probe.
|
||||
// dictionary_: NameDictionary to probe.
|
||||
// result_: used as scratch.
|
||||
// index_: will hold an index of entry if lookup is successful.
|
||||
// might alias with result_.
|
||||
@ -6364,12 +6362,12 @@ void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
// Compute the masked index: (hash + i + i * i) & mask.
|
||||
__ movq(scratch, Operand(rsp, 2 * kPointerSize));
|
||||
if (i > 0) {
|
||||
__ addl(scratch, Immediate(StringDictionary::GetProbeOffset(i)));
|
||||
__ addl(scratch, Immediate(NameDictionary::GetProbeOffset(i)));
|
||||
}
|
||||
__ and_(scratch, Operand(rsp, 0));
|
||||
|
||||
// Scale the index by multiplying by the entry size.
|
||||
ASSERT(StringDictionary::kEntrySize == 3);
|
||||
ASSERT(NameDictionary::kEntrySize == 3);
|
||||
__ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3.
|
||||
|
||||
// Having undefined at this place means the name is not contained.
|
||||
@ -6386,15 +6384,20 @@ void StringDictionaryLookupStub::Generate(MacroAssembler* masm) {
|
||||
__ j(equal, &in_dictionary);
|
||||
|
||||
if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
|
||||
// If we hit a non internalized string key during negative lookup
|
||||
// we have to bailout as this key might be equal to the
|
||||
// If we hit a key that is not a unique name during negative
|
||||
// lookup we have to bailout as this key might be equal to the
|
||||
// key we are looking for.
|
||||
|
||||
// Check if the entry name is not an internalized string.
|
||||
// Check if the entry name is not a unique name.
|
||||
Label cont;
|
||||
__ movq(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
|
||||
__ testb(FieldOperand(scratch, Map::kInstanceTypeOffset),
|
||||
Immediate(kIsInternalizedMask));
|
||||
__ j(zero, &maybe_in_dictionary);
|
||||
__ j(not_zero, &cont);
|
||||
__ cmpb(FieldOperand(scratch, Map::kInstanceTypeOffset),
|
||||
Immediate(static_cast<int8_t>(SYMBOL_TYPE)));
|
||||
__ j(not_equal, &maybe_in_dictionary);
|
||||
__ bind(&cont);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,14 +316,14 @@ class NumberToStringStub: public PlatformCodeStub {
|
||||
};
|
||||
|
||||
|
||||
class StringDictionaryLookupStub: public PlatformCodeStub {
|
||||
class NameDictionaryLookupStub: public PlatformCodeStub {
|
||||
public:
|
||||
enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
|
||||
|
||||
StringDictionaryLookupStub(Register dictionary,
|
||||
Register result,
|
||||
Register index,
|
||||
LookupMode mode)
|
||||
NameDictionaryLookupStub(Register dictionary,
|
||||
Register result,
|
||||
Register index,
|
||||
LookupMode mode)
|
||||
: dictionary_(dictionary), result_(result), index_(index), mode_(mode) { }
|
||||
|
||||
void Generate(MacroAssembler* masm);
|
||||
@ -332,7 +332,7 @@ class StringDictionaryLookupStub: public PlatformCodeStub {
|
||||
Label* miss,
|
||||
Label* done,
|
||||
Register properties,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register r0);
|
||||
|
||||
static void GeneratePositiveLookup(MacroAssembler* masm,
|
||||
@ -350,14 +350,14 @@ class StringDictionaryLookupStub: public PlatformCodeStub {
|
||||
static const int kTotalProbes = 20;
|
||||
|
||||
static const int kCapacityOffset =
|
||||
StringDictionary::kHeaderSize +
|
||||
StringDictionary::kCapacityIndex * kPointerSize;
|
||||
NameDictionary::kHeaderSize +
|
||||
NameDictionary::kCapacityIndex * kPointerSize;
|
||||
|
||||
static const int kElementsStartOffset =
|
||||
StringDictionary::kHeaderSize +
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
NameDictionary::kHeaderSize +
|
||||
NameDictionary::kElementsStartIndex * kPointerSize;
|
||||
|
||||
Major MajorKey() { return StringDictionaryLookup; }
|
||||
Major MajorKey() { return NameDictionaryLookup; }
|
||||
|
||||
int MinorKey() {
|
||||
return DictionaryBits::encode(dictionary_.code()) |
|
||||
|
@ -60,11 +60,11 @@ static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
|
||||
|
||||
// Generated code falls through if the receiver is a regular non-global
|
||||
// JS object with slow properties and no interceptors.
|
||||
static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register r0,
|
||||
Register r1,
|
||||
Label* miss) {
|
||||
static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register r0,
|
||||
Register r1,
|
||||
Label* miss) {
|
||||
// Register usage:
|
||||
// receiver: holds the receiver on entry and is unchanged.
|
||||
// r0: used to hold receiver instance type.
|
||||
@ -127,21 +127,21 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
|
||||
Label done;
|
||||
|
||||
// Probe the dictionary.
|
||||
StringDictionaryLookupStub::GeneratePositiveLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
elements,
|
||||
name,
|
||||
r0,
|
||||
r1);
|
||||
NameDictionaryLookupStub::GeneratePositiveLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
elements,
|
||||
name,
|
||||
r0,
|
||||
r1);
|
||||
|
||||
// If probing finds an entry in the dictionary, r1 contains the
|
||||
// index into the dictionary. Check that the value is a normal
|
||||
// property.
|
||||
__ bind(&done);
|
||||
const int kElementsStartOffset =
|
||||
StringDictionary::kHeaderSize +
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
NameDictionary::kHeaderSize +
|
||||
NameDictionary::kElementsStartIndex * kPointerSize;
|
||||
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
|
||||
__ Test(Operand(elements, r1, times_pointer_size,
|
||||
kDetailsOffset - kHeapObjectTag),
|
||||
@ -184,21 +184,21 @@ static void GenerateDictionaryStore(MacroAssembler* masm,
|
||||
Label done;
|
||||
|
||||
// Probe the dictionary.
|
||||
StringDictionaryLookupStub::GeneratePositiveLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
elements,
|
||||
name,
|
||||
scratch0,
|
||||
scratch1);
|
||||
NameDictionaryLookupStub::GeneratePositiveLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
elements,
|
||||
name,
|
||||
scratch0,
|
||||
scratch1);
|
||||
|
||||
// If probing finds an entry in the dictionary, scratch0 contains the
|
||||
// index into the dictionary. Check that the value is a normal
|
||||
// property that is not read only.
|
||||
__ bind(&done);
|
||||
const int kElementsStartOffset =
|
||||
StringDictionary::kHeaderSize +
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
NameDictionary::kHeaderSize +
|
||||
NameDictionary::kElementsStartIndex * kPointerSize;
|
||||
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
|
||||
const int kTypeAndReadOnlyMask =
|
||||
(PropertyDetails::TypeField::kMask |
|
||||
@ -313,31 +313,37 @@ static void GenerateFastArrayLoad(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Checks whether a key is an array index string or an internalized string.
|
||||
// Falls through if the key is an internalized string.
|
||||
static void GenerateKeyStringCheck(MacroAssembler* masm,
|
||||
Register key,
|
||||
Register map,
|
||||
Register hash,
|
||||
Label* index_string,
|
||||
Label* not_internalized) {
|
||||
// Checks whether a key is an array index string or a unique name.
|
||||
// Falls through if the key is a unique name.
|
||||
static void GenerateKeyNameCheck(MacroAssembler* masm,
|
||||
Register key,
|
||||
Register map,
|
||||
Register hash,
|
||||
Label* index_string,
|
||||
Label* not_unique) {
|
||||
// Register use:
|
||||
// key - holds the key and is unchanged. Assumed to be non-smi.
|
||||
// Scratch registers:
|
||||
// map - used to hold the map of the key.
|
||||
// hash - used to hold the hash of the key.
|
||||
__ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
|
||||
__ j(above_equal, not_internalized);
|
||||
Label unique;
|
||||
__ CmpObjectType(key, LAST_UNIQUE_NAME_TYPE, map);
|
||||
__ j(above, not_unique);
|
||||
STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
|
||||
__ j(equal, &unique);
|
||||
|
||||
// Is the string an array index, with cached numeric value?
|
||||
__ movl(hash, FieldOperand(key, String::kHashFieldOffset));
|
||||
__ testl(hash, Immediate(String::kContainsCachedArrayIndexMask));
|
||||
__ movl(hash, FieldOperand(key, Name::kHashFieldOffset));
|
||||
__ testl(hash, Immediate(Name::kContainsCachedArrayIndexMask));
|
||||
__ j(zero, index_string); // The value in hash is used at jump target.
|
||||
|
||||
// Is the string internalized?
|
||||
STATIC_ASSERT(kInternalizedTag != 0);
|
||||
__ testb(FieldOperand(map, Map::kInstanceTypeOffset),
|
||||
Immediate(kIsInternalizedMask));
|
||||
__ j(zero, not_internalized);
|
||||
__ j(zero, not_unique);
|
||||
|
||||
__ bind(&unique);
|
||||
}
|
||||
|
||||
|
||||
@ -348,11 +354,11 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
// -- rdx : receiver
|
||||
// -- rsp[0] : return address
|
||||
// -----------------------------------
|
||||
Label slow, check_string, index_smi, index_string, property_array_property;
|
||||
Label slow, check_name, index_smi, index_name, property_array_property;
|
||||
Label probe_dictionary, check_number_dictionary;
|
||||
|
||||
// Check that the key is a smi.
|
||||
__ JumpIfNotSmi(rax, &check_string);
|
||||
__ JumpIfNotSmi(rax, &check_name);
|
||||
__ bind(&index_smi);
|
||||
// Now the key is known to be a smi. This place is also jumped to from below
|
||||
// where a numeric string is converted to a smi.
|
||||
@ -397,8 +403,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ IncrementCounter(counters->keyed_load_generic_slow(), 1);
|
||||
GenerateRuntimeGetProperty(masm);
|
||||
|
||||
__ bind(&check_string);
|
||||
GenerateKeyStringCheck(masm, rax, rcx, rbx, &index_string, &slow);
|
||||
__ bind(&check_name);
|
||||
GenerateKeyNameCheck(masm, rax, rcx, rbx, &index_name, &slow);
|
||||
|
||||
GenerateKeyedLoadReceiverCheck(
|
||||
masm, rdx, rcx, Map::kHasNamedInterceptor, &slow);
|
||||
@ -499,7 +505,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
__ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
|
||||
__ ret(0);
|
||||
|
||||
__ bind(&index_string);
|
||||
__ bind(&index_name);
|
||||
__ IndexFromHash(rbx, rax);
|
||||
__ jmp(&index_smi);
|
||||
}
|
||||
@ -900,7 +906,7 @@ void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
|
||||
// Get the receiver of the function from the stack.
|
||||
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
|
||||
|
||||
GenerateStringDictionaryReceiverCheck(masm, rdx, rax, rbx, &miss);
|
||||
GenerateNameDictionaryReceiverCheck(masm, rdx, rax, rbx, &miss);
|
||||
|
||||
// rax: elements
|
||||
// Search the dictionary placing the result in rdi.
|
||||
@ -1020,11 +1026,11 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
|
||||
|
||||
Label do_call, slow_call, slow_load;
|
||||
Label check_number_dictionary, check_string, lookup_monomorphic_cache;
|
||||
Label index_smi, index_string;
|
||||
Label check_number_dictionary, check_name, lookup_monomorphic_cache;
|
||||
Label index_smi, index_name;
|
||||
|
||||
// Check that the key is a smi.
|
||||
__ JumpIfNotSmi(rcx, &check_string);
|
||||
__ JumpIfNotSmi(rcx, &check_name);
|
||||
|
||||
__ bind(&index_smi);
|
||||
// Now the key is known to be a smi. This place is also jumped to from below
|
||||
@ -1072,10 +1078,10 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
__ movq(rdi, rax);
|
||||
__ jmp(&do_call);
|
||||
|
||||
__ bind(&check_string);
|
||||
GenerateKeyStringCheck(masm, rcx, rax, rbx, &index_string, &slow_call);
|
||||
__ bind(&check_name);
|
||||
GenerateKeyNameCheck(masm, rcx, rax, rbx, &index_name, &slow_call);
|
||||
|
||||
// The key is known to be an internalized string.
|
||||
// The key is known to be a unique name.
|
||||
// If the receiver is a regular JS object with slow properties then do
|
||||
// a quick inline probe of the receiver's dictionary.
|
||||
// Otherwise do the monomorphic cache probe.
|
||||
@ -1102,14 +1108,14 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||
__ bind(&slow_call);
|
||||
// This branch is taken if:
|
||||
// - the receiver requires boxing or access check,
|
||||
// - the key is neither smi nor internalized string,
|
||||
// - the key is neither smi nor a unique name,
|
||||
// - the value loaded is not a function,
|
||||
// - there is hope that the runtime will create a monomorphic call stub
|
||||
// that will get fetched next time.
|
||||
__ IncrementCounter(counters->keyed_call_generic_slow(), 1);
|
||||
GenerateMiss(masm, argc);
|
||||
|
||||
__ bind(&index_string);
|
||||
__ bind(&index_name);
|
||||
__ IndexFromHash(rbx, rcx);
|
||||
// Now jump to the place where smi keys are handled.
|
||||
__ jmp(&index_smi);
|
||||
@ -1127,10 +1133,10 @@ void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
|
||||
// rsp[(argc + 1) * 8] : argument 0 = receiver
|
||||
// -----------------------------------
|
||||
|
||||
// Check if the name is a string.
|
||||
// Check if the name is really a name.
|
||||
Label miss;
|
||||
__ JumpIfSmi(rcx, &miss);
|
||||
Condition cond = masm->IsObjectStringType(rcx, rax, rax);
|
||||
Condition cond = masm->IsObjectNameType(rcx, rax, rax);
|
||||
__ j(NegateCondition(cond), &miss);
|
||||
CallICBase::GenerateNormal(masm, argc);
|
||||
__ bind(&miss);
|
||||
@ -1339,7 +1345,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
||||
// -----------------------------------
|
||||
Label miss;
|
||||
|
||||
GenerateStringDictionaryReceiverCheck(masm, rax, rdx, rbx, &miss);
|
||||
GenerateNameDictionaryReceiverCheck(masm, rax, rdx, rbx, &miss);
|
||||
|
||||
// rdx: elements
|
||||
// Search the dictionary placing the result in rax.
|
||||
@ -1466,7 +1472,7 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
|
||||
|
||||
Label miss;
|
||||
|
||||
GenerateStringDictionaryReceiverCheck(masm, rdx, rbx, rdi, &miss);
|
||||
GenerateNameDictionaryReceiverCheck(masm, rdx, rbx, rdi, &miss);
|
||||
|
||||
GenerateDictionaryStore(masm, &miss, rbx, rcx, rax, r8, r9);
|
||||
Counters* counters = masm->isolate()->counters();
|
||||
|
@ -3017,6 +3017,19 @@ void MacroAssembler::AssertString(Register object) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::AssertName(Register object) {
|
||||
if (emit_debug_code()) {
|
||||
testb(object, Immediate(kSmiTagMask));
|
||||
Check(not_equal, "Operand is a smi and not a name");
|
||||
push(object);
|
||||
movq(object, FieldOperand(object, HeapObject::kMapOffset));
|
||||
CmpInstanceType(object, LAST_NAME_TYPE);
|
||||
pop(object);
|
||||
Check(below_equal, "Operand is not a name");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::AssertRootValue(Register src,
|
||||
Heap::RootListIndex root_value_index,
|
||||
const char* message) {
|
||||
@ -3041,6 +3054,16 @@ Condition MacroAssembler::IsObjectStringType(Register heap_object,
|
||||
}
|
||||
|
||||
|
||||
Condition MacroAssembler::IsObjectNameType(Register heap_object,
|
||||
Register map,
|
||||
Register instance_type) {
|
||||
movq(map, FieldOperand(heap_object, HeapObject::kMapOffset));
|
||||
movzxbl(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
|
||||
cmpb(instance_type, Immediate(static_cast<int8_t>(LAST_NAME_TYPE)));
|
||||
return below_equal;
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::TryGetFunctionPrototype(Register function,
|
||||
Register result,
|
||||
Label* miss,
|
||||
|
@ -922,6 +922,15 @@ class MacroAssembler: public Assembler {
|
||||
Register map,
|
||||
Register instance_type);
|
||||
|
||||
// Check if the object in register heap_object is a name. Afterwards the
|
||||
// register map contains the object map and the register instance_type
|
||||
// contains the instance_type. The registers map and instance_type can be the
|
||||
// same in which case it contains the instance type afterwards. Either of the
|
||||
// registers map and instance_type can be the same as heap_object.
|
||||
Condition IsObjectNameType(Register heap_object,
|
||||
Register map,
|
||||
Register instance_type);
|
||||
|
||||
// FCmp compares and pops the two values on top of the FPU stack.
|
||||
// The flag results are similar to integer cmp, but requires unsigned
|
||||
// jcc instructions (je, ja, jae, jb, jbe, je, and jz).
|
||||
@ -965,6 +974,9 @@ class MacroAssembler: public Assembler {
|
||||
// Abort execution if argument is not a string, enabled via --debug-code.
|
||||
void AssertString(Register object);
|
||||
|
||||
// Abort execution if argument is not a name, enabled via --debug-code.
|
||||
void AssertName(Register object);
|
||||
|
||||
// Abort execution if argument is not the root value with the given index,
|
||||
// enabled via --debug-code.
|
||||
void AssertRootValue(Register src,
|
||||
|
@ -110,14 +110,14 @@ static void ProbeTable(Isolate* isolate,
|
||||
// the property. This function may return false negatives, so miss_label
|
||||
// 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 an internalized string and receiver must be a heap object.
|
||||
// Name must be unique and receiver must be a heap object.
|
||||
static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
|
||||
Label* miss_label,
|
||||
Register receiver,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register r0,
|
||||
Register r1) {
|
||||
ASSERT(name->IsInternalizedString());
|
||||
ASSERT(name->IsUniqueName());
|
||||
Counters* counters = masm->isolate()->counters();
|
||||
__ IncrementCounter(counters->negative_lookups(), 1);
|
||||
__ IncrementCounter(counters->negative_lookups_miss(), 1);
|
||||
@ -146,12 +146,12 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
|
||||
__ j(not_equal, miss_label);
|
||||
|
||||
Label done;
|
||||
StringDictionaryLookupStub::GenerateNegativeLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
properties,
|
||||
name,
|
||||
r1);
|
||||
NameDictionaryLookupStub::GenerateNegativeLookup(masm,
|
||||
miss_label,
|
||||
&done,
|
||||
properties,
|
||||
name,
|
||||
r1);
|
||||
__ bind(&done);
|
||||
__ DecrementCounter(counters->negative_lookups_miss(), 1);
|
||||
}
|
||||
@ -193,7 +193,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
__ JumpIfSmi(receiver, &miss);
|
||||
|
||||
// Get the map of the receiver and compute the hash.
|
||||
__ movl(scratch, FieldOperand(name, String::kHashFieldOffset));
|
||||
__ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
|
||||
// Use only the low 32 bits of the map pointer.
|
||||
__ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
__ xor_(scratch, Immediate(flags));
|
||||
@ -205,7 +205,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
ProbeTable(isolate, masm, flags, kPrimary, receiver, name, scratch);
|
||||
|
||||
// Primary miss: Compute hash for secondary probe.
|
||||
__ movl(scratch, FieldOperand(name, String::kHashFieldOffset));
|
||||
__ movl(scratch, FieldOperand(name, Name::kHashFieldOffset));
|
||||
__ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
|
||||
__ xor_(scratch, Immediate(flags));
|
||||
__ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
|
||||
@ -533,7 +533,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
void Compile(MacroAssembler* masm,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
LookupResult* lookup,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
@ -565,7 +565,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
Register scratch3,
|
||||
Handle<JSObject> interceptor_holder,
|
||||
LookupResult* lookup,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
const CallOptimization& optimization,
|
||||
Label* miss_label) {
|
||||
ASSERT(optimization.is_constant_call());
|
||||
@ -658,7 +658,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Register scratch3,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> interceptor_holder,
|
||||
Label* miss_label) {
|
||||
Register holder =
|
||||
@ -746,7 +746,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
|
||||
Handle<JSObject> object,
|
||||
int index,
|
||||
Handle<Map> transition,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register receiver_reg,
|
||||
Register name_reg,
|
||||
Register scratch1,
|
||||
@ -874,7 +874,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
|
||||
// property.
|
||||
static void GenerateCheckPropertyCell(MacroAssembler* masm,
|
||||
Handle<GlobalObject> global,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register scratch,
|
||||
Label* miss) {
|
||||
Handle<JSGlobalPropertyCell> cell =
|
||||
@ -892,7 +892,7 @@ static void GenerateCheckPropertyCell(MacroAssembler* masm,
|
||||
static void GenerateCheckPropertyCells(MacroAssembler* masm,
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Register scratch,
|
||||
Label* miss) {
|
||||
Handle<JSObject> current = object;
|
||||
@ -923,7 +923,7 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
|
||||
Register holder_reg,
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
int save_at_depth,
|
||||
Label* miss,
|
||||
PrototypeCheckType check) {
|
||||
@ -957,11 +957,12 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
|
||||
if (!current->HasFastProperties() &&
|
||||
!current->IsJSGlobalObject() &&
|
||||
!current->IsJSGlobalProxy()) {
|
||||
if (!name->IsInternalizedString()) {
|
||||
name = factory()->InternalizeString(name);
|
||||
if (!name->IsUniqueName()) {
|
||||
ASSERT(name->IsString());
|
||||
name = factory()->InternalizeString(Handle<String>::cast(name));
|
||||
}
|
||||
ASSERT(current->property_dictionary()->FindEntry(*name) ==
|
||||
StringDictionary::kNotFound);
|
||||
NameDictionary::kNotFound);
|
||||
|
||||
GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
|
||||
scratch1, scratch2);
|
||||
@ -1047,7 +1048,7 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend(
|
||||
Handle<JSObject> object,
|
||||
Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* success,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
Label miss;
|
||||
@ -1065,21 +1066,21 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend(
|
||||
|
||||
// Probe the dictionary.
|
||||
Label probe_done;
|
||||
StringDictionaryLookupStub::GeneratePositiveLookup(masm(),
|
||||
&miss,
|
||||
&probe_done,
|
||||
dictionary,
|
||||
this->name(),
|
||||
scratch2(),
|
||||
scratch3());
|
||||
NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
|
||||
&miss,
|
||||
&probe_done,
|
||||
dictionary,
|
||||
this->name(),
|
||||
scratch2(),
|
||||
scratch3());
|
||||
__ bind(&probe_done);
|
||||
|
||||
// If probing finds an entry in the dictionary, scratch3 contains the
|
||||
// index into the dictionary. Check that the value is the callback.
|
||||
Register index = scratch3();
|
||||
const int kElementsStartOffset =
|
||||
StringDictionary::kHeaderSize +
|
||||
StringDictionary::kElementsStartIndex * kPointerSize;
|
||||
NameDictionary::kHeaderSize +
|
||||
NameDictionary::kElementsStartIndex * kPointerSize;
|
||||
const int kValueOffset = kElementsStartOffset + kPointerSize;
|
||||
__ movq(scratch2(),
|
||||
Operand(dictionary, index, times_pointer_size,
|
||||
@ -1097,7 +1098,7 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend(
|
||||
void BaseLoadStubCompiler::NonexistentHandlerFrontend(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> last,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* success,
|
||||
Handle<GlobalObject> global) {
|
||||
Label miss;
|
||||
@ -1200,7 +1201,7 @@ void BaseLoadStubCompiler::GenerateLoadInterceptor(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> interceptor_holder,
|
||||
LookupResult* lookup,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
ASSERT(interceptor_holder->HasNamedInterceptor());
|
||||
ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
|
||||
|
||||
@ -1288,7 +1289,7 @@ void BaseLoadStubCompiler::GenerateLoadInterceptor(
|
||||
}
|
||||
|
||||
|
||||
void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
|
||||
void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
|
||||
if (kind_ == Code::KEYED_CALL_IC) {
|
||||
__ Cmp(rcx, name);
|
||||
__ j(not_equal, miss);
|
||||
@ -1298,7 +1299,7 @@ void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) {
|
||||
|
||||
void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Label* miss) {
|
||||
ASSERT(holder->IsGlobalObject());
|
||||
|
||||
@ -1356,7 +1357,7 @@ void CallStubCompiler::GenerateMissBranch() {
|
||||
Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
PropertyIndex index,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// rcx : function name
|
||||
// rsp[0] : return address
|
||||
@ -2145,7 +2146,7 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
|
||||
|
||||
void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
CheckType check,
|
||||
Label* success) {
|
||||
// ----------- S t a t e -------------
|
||||
@ -2261,13 +2262,13 @@ void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
|
||||
Handle<Code> CallStubCompiler::CompileCallConstant(
|
||||
Handle<Object> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
CheckType check,
|
||||
Handle<JSFunction> function) {
|
||||
if (HasCustomCallGenerator(function)) {
|
||||
Handle<Code> code = CompileCustomCall(object, holder,
|
||||
Handle<JSGlobalPropertyCell>::null(),
|
||||
function, name);
|
||||
function, Handle<String>::cast(name));
|
||||
// A null handle means bail out to the regular compiler code below.
|
||||
if (!code.is_null()) return code;
|
||||
}
|
||||
@ -2285,7 +2286,7 @@ Handle<Code> CallStubCompiler::CompileCallConstant(
|
||||
|
||||
Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
|
||||
Handle<JSObject> holder,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// rcx : function name
|
||||
// rsp[0] : return address
|
||||
@ -2348,7 +2349,7 @@ Handle<Code> CallStubCompiler::CompileCallGlobal(
|
||||
Handle<GlobalObject> holder,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
Handle<JSFunction> function,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// rcx : function name
|
||||
// rsp[0] : return address
|
||||
@ -2360,7 +2361,8 @@ Handle<Code> CallStubCompiler::CompileCallGlobal(
|
||||
// -----------------------------------
|
||||
|
||||
if (HasCustomCallGenerator(function)) {
|
||||
Handle<Code> code = CompileCustomCall(object, holder, cell, function, name);
|
||||
Handle<Code> code = CompileCustomCall(
|
||||
object, holder, cell, function, Handle<String>::cast(name));
|
||||
// A null handle means bail out to the regular compiler code below.
|
||||
if (!code.is_null()) return code;
|
||||
}
|
||||
@ -2409,7 +2411,7 @@ Handle<Code> CallStubCompiler::CompileCallGlobal(
|
||||
Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
|
||||
int index,
|
||||
Handle<Map> transition,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : value
|
||||
// -- rcx : name
|
||||
@ -2440,7 +2442,7 @@ Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
|
||||
|
||||
|
||||
Handle<Code> StoreStubCompiler::CompileStoreCallback(
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<ExecutableAccessorInfo> callback) {
|
||||
@ -2527,7 +2529,7 @@ void StoreStubCompiler::GenerateStoreViaSetter(
|
||||
|
||||
|
||||
Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<JSObject> holder,
|
||||
Handle<JSFunction> setter) {
|
||||
@ -2556,7 +2558,7 @@ Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
|
||||
|
||||
Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
|
||||
Handle<JSObject> receiver,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : value
|
||||
// -- rcx : name
|
||||
@ -2603,7 +2605,7 @@ Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
|
||||
Handle<Code> StoreStubCompiler::CompileStoreGlobal(
|
||||
Handle<GlobalObject> object,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : value
|
||||
// -- rcx : name
|
||||
@ -2651,7 +2653,7 @@ Handle<Code> StoreStubCompiler::CompileStoreGlobal(
|
||||
Handle<Code> KeyedStoreStubCompiler::CompileStoreField(Handle<JSObject> object,
|
||||
int index,
|
||||
Handle<Map> transition,
|
||||
Handle<String> name) {
|
||||
Handle<Name> name) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : value
|
||||
// -- rcx : key
|
||||
@ -2756,7 +2758,7 @@ Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
|
||||
Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
|
||||
Handle<JSObject> object,
|
||||
Handle<JSObject> last,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Handle<GlobalObject> global) {
|
||||
Label success;
|
||||
|
||||
@ -2787,7 +2789,7 @@ Register* KeyedLoadStubCompiler::registers() {
|
||||
}
|
||||
|
||||
|
||||
void KeyedLoadStubCompiler::GenerateNameCheck(Handle<String> name,
|
||||
void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name,
|
||||
Register name_reg,
|
||||
Label* miss) {
|
||||
__ Cmp(name_reg, name);
|
||||
@ -2836,7 +2838,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
|
||||
Handle<JSObject> object,
|
||||
Handle<GlobalObject> global,
|
||||
Handle<JSGlobalPropertyCell> cell,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
bool is_dont_delete) {
|
||||
Label success, miss;
|
||||
// TODO(verwaest): Directly store to rax. Currently we cannot do this, since
|
||||
@ -2903,7 +2905,7 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
|
||||
Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
|
||||
MapHandleList* receiver_maps,
|
||||
CodeHandleList* handlers,
|
||||
Handle<String> name,
|
||||
Handle<Name> name,
|
||||
Code::StubType type,
|
||||
IcCheckType check) {
|
||||
Label miss;
|
||||
|
@ -115,7 +115,7 @@ TestSet()
|
||||
|
||||
|
||||
function TestMap() {
|
||||
var map = new Map;
|
||||
var map = new Map
|
||||
for (var i in symbols) {
|
||||
map.set(symbols[i], i)
|
||||
}
|
||||
@ -125,3 +125,100 @@ function TestMap() {
|
||||
}
|
||||
}
|
||||
TestMap()
|
||||
|
||||
|
||||
|
||||
function TestKeySet(obj) {
|
||||
// Set the even symbols via assignment.
|
||||
for (var i = 0; i < symbols.length; i += 2) {
|
||||
obj[symbols[i]] = i
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function TestKeyDefine(obj) {
|
||||
// Set the odd symbols via defineProperty (as non-enumerable).
|
||||
for (var i = 1; i < symbols.length; i += 2) {
|
||||
Object.defineProperty(obj, symbols[i], {value: i, configurable: true})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function TestKeyGet(obj) {
|
||||
var obj2 = Object.create(obj)
|
||||
for (var i in symbols) {
|
||||
assertEquals(i|0, obj[symbols[i]])
|
||||
assertEquals(i|0, obj2[symbols[i]])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function TestKeyHas() {
|
||||
for (var i in symbols) {
|
||||
assertTrue(symbols[i] in obj)
|
||||
assertTrue(Object.hasOwnProperty.call(obj, symbols[i]))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function TestKeyEnum(obj) {
|
||||
// TODO(rossberg): symbols should not show up at all in for-in.
|
||||
var found = [];
|
||||
names: for (var name in obj) {
|
||||
for (var i in symbols) {
|
||||
if (name === symbols[i]) {
|
||||
found[i] = true;
|
||||
continue names;
|
||||
}
|
||||
}
|
||||
}
|
||||
// All even symbols should have been enumerated.
|
||||
for (var i = 0; i < symbols.length; i += 2) {
|
||||
assertTrue(i in found)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function TestKeyKeys(obj) {
|
||||
// TODO(rossberg): symbols should not be returned by Object.keys.
|
||||
assertEquals(symbols.length / 2, Object.keys(obj).length)
|
||||
assertTrue(symbols.length <= Object.getOwnPropertyNames(obj).length)
|
||||
}
|
||||
|
||||
|
||||
function TestKeyDescriptor(obj) {
|
||||
for (var i in symbols) {
|
||||
var desc = Object.getOwnPropertyDescriptor(obj, symbols[i]);
|
||||
assertEquals(i|0, desc.value)
|
||||
assertTrue(desc.configurable)
|
||||
assertEquals(i % 2 == 0, desc.writable)
|
||||
assertEquals(i % 2 == 0, desc.enumerable)
|
||||
assertEquals(i % 2 == 0,
|
||||
Object.prototype.propertyIsEnumerable.call(obj, symbols[i]))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function TestKeyDelete(obj) {
|
||||
for (var i in symbols) {
|
||||
delete obj[symbols[i]]
|
||||
}
|
||||
for (var i in symbols) {
|
||||
assertEquals(undefined, Object.getOwnPropertyDescriptor(obj, symbols[i]))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var objs = [{}, [], Object.create(null), Object(1), new Map, function(){}]
|
||||
|
||||
for (var i in objs) {
|
||||
var obj = objs[i]
|
||||
TestKeySet(obj)
|
||||
TestKeyDefine(obj)
|
||||
TestKeyGet(obj)
|
||||
TestKeyHas(obj)
|
||||
TestKeyEnum(obj)
|
||||
TestKeyKeys(obj)
|
||||
TestKeyDescriptor(obj)
|
||||
TestKeyDelete(obj)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user