SmallMapList* map_set = instr->hydrogen()->map_set();
for (int i = 0; i < map_set->length() - 1; i++) {
Handle<Map> map = map_set->at(i);
- __ CompareMap(reg, scratch, map, &success, instr->hydrogen()->mode());
+ __ CompareMap(reg, scratch, map, &success, REQUIRE_EXACT_MAP);
__ b(eq, &success);
}
Handle<Map> map = map_set->last();
- DoCheckMapCommon(reg, scratch, map, instr->hydrogen()->mode(),
- instr->environment());
+ DoCheckMapCommon(reg, scratch, map, REQUIRE_EXACT_MAP, instr->environment());
__ bind(&success);
}
class HCheckMaps: public HTemplateInstruction<2> {
public:
HCheckMaps(HValue* value, Handle<Map> map, Zone* zone,
- HValue* typecheck = NULL,
- CompareMapMode mode = REQUIRE_EXACT_MAP) : mode_(mode) {
+ HValue* typecheck = NULL) {
SetOperandAt(0, value);
// If callers don't depend on a typecheck, they can pass in NULL. In that
// case we use a copy of the |value| argument as a dummy value.
SetGVNFlag(kDependsOnElementsKind);
map_set()->Add(map, zone);
}
- HCheckMaps(HValue* value, SmallMapList* maps, Zone* zone,
- CompareMapMode mode = REQUIRE_EXACT_MAP) : mode_(mode) {
+ HCheckMaps(HValue* value, SmallMapList* maps, Zone* zone) {
SetOperandAt(0, value);
SetOperandAt(1, value);
set_representation(Representation::Tagged());
HValue* value() { return OperandAt(0); }
SmallMapList* map_set() { return &map_set_; }
- CompareMapMode mode() { return mode_; }
DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
private:
SmallMapList map_set_;
- CompareMapMode mode_;
};
HInstruction* instr = NULL;
if (expr->AsProperty()->IsArrayLength()) {
- // Note that in the monomorphic case IsArrayLength() is false because we
- // handle that it with a regular property load IC.
HValue* array = Pop();
AddInstruction(new(zone()) HCheckNonSmi(array));
HInstruction* mapcheck =
map = types->first();
if (map->is_dictionary_map()) monomorphic = false;
}
-
- // Try to see if this is an array length access.
- if (name->Equals(isolate()->heap()->length_symbol())) {
- bool is_array = false;
- bool fast_mode = false;
- bool map_mode = false;
- HInstruction* mapcheck = NULL;
-
- if (expr->IsMonomorphic()) {
- // Even if there is more than one map they all must be element
- // transition maps, so checking just one is ok.
- if (map->instance_type() == JS_ARRAY_TYPE) {
- is_array = true;
- map_mode = true;
- fast_mode = IsFastElementsKind(map->elements_kind());
- }
+ if (monomorphic) {
+ Handle<JSFunction> getter;
+ Handle<JSObject> holder;
+ if (LookupGetter(map, name, &getter, &holder)) {
+ AddCheckConstantFunction(holder, Top(), map);
+ if (FLAG_inline_accessors && TryInlineGetter(getter, expr)) return;
+ AddInstruction(new(zone()) HPushArgument(Pop()));
+ instr = new(zone()) HCallConstantFunction(getter, 1);
} else {
- // Since we will emit an instance check we have to conservatively
- // assume that some arrays will contain slow elements, so we set
- // fast_mode to false.
- map_mode = false;
- fast_mode = false;
- is_array = true;
- for (int i = 0; i < types->length(); i++) {
- Handle<Map> current_map = types->at(i);
- if (current_map->instance_type() != JS_ARRAY_TYPE) {
- is_array = false;
- break;
- }
- }
- }
-
- // It is an array length access so we produce a HJSArrayLength.
- if (is_array) {
- HValue* array = Pop();
- AddInstruction(new(zone()) HCheckNonSmi(array));
- mapcheck = map_mode ?
- HInstruction::cast(
- new(zone()) HCheckMaps(array, map, zone(), NULL,
- ALLOW_ELEMENT_TRANSITION_MAPS)) :
- HInstruction::cast(
- HCheckInstanceType::NewIsJSArray(array, zone()));
- AddInstruction(mapcheck);
- instr = new(zone()) HJSArrayLength(
- array, mapcheck, fast_mode ? HType::Smi() : HType::Tagged());
+ instr = BuildLoadNamedMonomorphic(Pop(), name, expr, map);
}
+ } else if (types != NULL && types->length() > 1) {
+ return HandlePolymorphicLoadNamedField(expr, Pop(), types, name);
+ } else {
+ instr = BuildLoadNamedGeneric(Pop(), name, expr);
}
- // We cannot know if it was an array length access so we handle it as
- // a regular property access.
- if (instr == NULL) {
- if (monomorphic) {
- Handle<JSFunction> getter;
- Handle<JSObject> holder;
- if (LookupGetter(map, name, &getter, &holder)) {
- AddCheckConstantFunction(holder, Top(), map);
- if (FLAG_inline_accessors && TryInlineGetter(getter, expr)) return;
- AddInstruction(new(zone()) HPushArgument(Pop()));
- instr = new(zone()) HCallConstantFunction(getter, 1);
- } else {
- instr = BuildLoadNamedMonomorphic(Pop(), name, expr, map);
- }
- } else if (types != NULL && types->length() > 1) {
- return HandlePolymorphicLoadNamedField(expr, Pop(), types, name);
- } else {
- instr = BuildLoadNamedGeneric(Pop(), name, expr);
- }
- }
} else {
CHECK_ALIVE(VisitForValue(expr->key()));
SmallMapList* map_set = instr->hydrogen()->map_set();
for (int i = 0; i < map_set->length() - 1; i++) {
Handle<Map> map = map_set->at(i);
- __ CompareMap(reg, map, &success, instr->hydrogen()->mode());
+ __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP);
__ j(equal, &success);
}
Handle<Map> map = map_set->last();
- DoCheckMapCommon(reg, map, instr->hydrogen()->mode(), instr->environment());
+ DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr->environment());
__ bind(&success);
}
return Smi::FromInt(String::cast(*string)->length());
}
+ // Use specialized code for getting the length of arrays.
+ if (object->IsJSArray() &&
+ name->Equals(isolate()->heap()->length_symbol())) {
+ Handle<Code> stub;
+ if (state == UNINITIALIZED) {
+ stub = pre_monomorphic_stub();
+ } else if (state == PREMONOMORPHIC) {
+ stub = isolate()->builtins()->LoadIC_ArrayLength();
+ } else if (state != MEGAMORPHIC) {
+ stub = megamorphic_stub();
+ }
+ if (!stub.is_null()) {
+ set_target(*stub);
+#ifdef DEBUG
+ if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
+#endif
+ }
+ return JSArray::cast(*object)->length();
+ }
+
// Use specialized code for getting prototype of functions.
if (object->IsJSFunction() &&
name->Equals(isolate()->heap()->prototype_symbol()) &&
if (!holder->HasFastProperties()) return;
code = isolate()->stub_cache()->ComputeLoadViaGetter(
name, receiver, holder, Handle<JSFunction>::cast(getter));
- } else if (holder->IsJSArray() &&
- name->Equals(isolate()->heap()->length_symbol())) {
- ASSERT(callback->IsForeign());
- ASSERT(reinterpret_cast<AccessorDescriptor*>(
- Handle<Foreign>::cast(callback)->foreign_address())
- == &Accessors::ArrayLength);
- // Use a "load field" IC for getting the array length.
- // Note that the resulting code object is marked as "Code::FIELD"
- // and not as "Code::CALLBACKS".
- code = isolate()->stub_cache()->ComputeLoadField(
- name, receiver, holder, JSArray::ArrayLengthIndex());
} else {
ASSERT(callback->IsForeign());
// No IC support for old-style native accessors.
for (int i = 0; i < map_set->length() - 1; i++) {
Handle<Map> map = map_set->at(i);
__ CompareMapAndBranch(
- reg, scratch, map, &success, eq, &success, instr->hydrogen()->mode());
+ reg, scratch, map, &success, eq, &success, REQUIRE_EXACT_MAP);
}
Handle<Map> map = map_set->last();
- DoCheckMapCommon(reg, scratch, map, instr->hydrogen()->mode(),
- instr->environment());
+ DoCheckMapCommon(reg, scratch, map, REQUIRE_EXACT_MAP, instr->environment());
__ bind(&success);
}
ACCESSORS(JSArray, length, Object, kLengthOffset)
-PropertyIndex JSArray::ArrayLengthIndex() {
- return PropertyIndex::NewHeaderIndex(kLengthOffset / kPointerSize);
-}
-
-
ACCESSORS(JSRegExp, data, Object, kDataOffset)
};
-class PropertyIndex;
-
-
// The JSArray describes JavaScript Arrays
// Such an array can be in one of two modes:
// - fast, backing storage is a FixedArray and length <= elements.length();
static const int kLengthOffset = JSObject::kHeaderSize;
static const int kSize = kLengthOffset + kPointerSize;
- static inline PropertyIndex ArrayLengthIndex();
- STATIC_ASSERT(kLengthOffset % kPointerSize == 0);
-
private:
// Expand the fixed array backing of a fast-case JSArray to at least
// the requested size.
SmallMapList* map_set = instr->hydrogen()->map_set();
for (int i = 0; i < map_set->length() - 1; i++) {
Handle<Map> map = map_set->at(i);
- __ CompareMap(reg, map, &success, instr->hydrogen()->mode());
+ __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP);
__ j(equal, &success);
}
Handle<Map> map = map_set->last();
- DoCheckMapCommon(reg, map, instr->hydrogen()->mode(), instr->environment());
+ DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr->environment());
__ bind(&success);
}
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --allow-natives-syntax
-
var a = [0,1,2,3];
assertEquals(0, a.length = 0);
t = a.length = 7;
assertEquals(7, t);
}
-
-function TestLengthAccess() {
- var TestGetLength = function(a, l, getLength, getKeyedLength) {
- assertEquals(l, getLength(a));
- assertEquals(l, getKeyedLength(a));
- }
-
- var Test = function(a, l, getLength, getKeyedLength) {
- // Make the ICs reach the state we want.
- TestGetLength(a, l, getLength, getKeyedLength);
- TestGetLength(a, l, getLength, getKeyedLength);
- TestGetLength(a, l, getLength, getKeyedLength);
- // Also test crankshaft.
- %OptimizeFunctionOnNextCall(getLength);
- %OptimizeFunctionOnNextCall(getKeyedLength);
- TestGetLength(a, l, getLength, getKeyedLength);
- }
-
- var getLength = function(a) { return a.length; }
- var getKeyedLength = function(a) { return a['length']; }
- Test(new Array(4), 4, getLength, getKeyedLength);
-
- getLength = function(a) { return a.length; }
- getKeyedLength = function(a) { return a['length']; }
- Test([1, 2, 3, 4], 4, getLength, getKeyedLength);
-
- getLength = function(a) { return a.length; }
- getKeyedLength = function(a) { return a['length']; }
- Test(Object.create(new Array(4)), 4, getLength, getKeyedLength);
-
- getLength = function(a) { return a.length; }
- getKeyedLength = function(a) { return a['length']; }
- // Set the 'length' of the global object.
- length = 4;
- var globalObject = (1,eval)("this");
- Test(globalObject, 4, getLength, getKeyedLength);
-}
-TestLengthAccess();
-