| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index 51ae7f5a44c29fc4b69f66651b95fcfef7a6f2fa..9edd440b4f0601bbabf1da9e765bf1b19d50a956 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -6613,6 +6613,8 @@ void HGraphBuilder::VisitProperty(Property* expr) {
|
|
|
| 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 =
|
| @@ -6648,23 +6650,74 @@ void HGraphBuilder::VisitProperty(Property* expr) {
|
| map = types->first();
|
| if (map->is_dictionary_map()) monomorphic = false;
|
| }
|
| - 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);
|
| +
|
| + // 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());
|
| + }
|
| } else {
|
| - instr = BuildLoadNamedMonomorphic(Pop(), name, expr, map);
|
| + // 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());
|
| }
|
| - } 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()));
|
|
|
|
|