~ubuntu-branches/ubuntu/saucy/libv8/saucy

« back to all changes in this revision

Viewing changes to src/arm/lithium-codegen-arm.cc

  • Committer: Package Import Robot
  • Author(s): Jérémy Lal
  • Date: 2012-04-07 16:26:13 UTC
  • mfrom: (15.1.27 sid)
  • Revision ID: package-import@ubuntu.com-20120407162613-dqo1m6w9r3fh8tst
Tags: 3.8.9.16-3
* mipsel build fixes :
  + v8_use_mips_abi_hardfloat=false, this lowers EABI requirements.
  + v8_can_use_fpu_instructions=false, detect if FPU is present.
  + set -Wno-unused-but-set-variable only on mipsel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2011 the V8 project authors. All rights reserved.
 
1
// Copyright 2012 the V8 project authors. All rights reserved.
2
2
// Redistribution and use in source and binary forms, with or without
3
3
// modification, are permitted provided that the following conditions are
4
4
// met:
262
262
 
263
263
bool LCodeGen::GenerateDeoptJumpTable() {
264
264
  // Check that the jump table is accessible from everywhere in the function
265
 
  // code, ie that offsets to the table can be encoded in the 24bit signed
 
265
  // code, i.e. that offsets to the table can be encoded in the 24bit signed
266
266
  // immediate of a branch instruction.
267
267
  // To simplify we consider the code size from the first instruction to the
268
268
  // end of the jump table. We also don't consider the pc load delta.
321
321
  if (op->IsRegister()) {
322
322
    return ToRegister(op->index());
323
323
  } else if (op->IsConstantOperand()) {
324
 
    __ mov(scratch, ToOperand(op));
 
324
    LConstantOperand* const_op = LConstantOperand::cast(op);
 
325
    Handle<Object> literal = chunk_->LookupLiteral(const_op);
 
326
    Representation r = chunk_->LookupLiteralRepresentation(const_op);
 
327
    if (r.IsInteger32()) {
 
328
      ASSERT(literal->IsNumber());
 
329
      __ mov(scratch, Operand(static_cast<int32_t>(literal->Number())));
 
330
    } else if (r.IsDouble()) {
 
331
      Abort("EmitLoadRegister: Unsupported double immediate.");
 
332
    } else {
 
333
      ASSERT(r.IsTagged());
 
334
      if (literal->IsSmi()) {
 
335
        __ mov(scratch, Operand(literal));
 
336
      } else {
 
337
       __ LoadHeapObject(scratch, Handle<HeapObject>::cast(literal));
 
338
      }
 
339
    }
325
340
    return scratch;
326
341
  } else if (op->IsStackSlot() || op->IsArgument()) {
327
342
    __ ldr(scratch, ToMemOperand(op));
370
385
}
371
386
 
372
387
 
 
388
Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
 
389
  Handle<Object> literal = chunk_->LookupLiteral(op);
 
390
  ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
 
391
  return literal;
 
392
}
 
393
 
 
394
 
 
395
bool LCodeGen::IsInteger32(LConstantOperand* op) const {
 
396
  return chunk_->LookupLiteralRepresentation(op).IsInteger32();
 
397
}
 
398
 
 
399
 
373
400
int LCodeGen::ToInteger32(LConstantOperand* op) const {
374
401
  Handle<Object> value = chunk_->LookupLiteral(op);
375
402
  ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
452
479
 
453
480
  WriteTranslation(environment->outer(), translation);
454
481
  int closure_id = DefineDeoptimizationLiteral(environment->closure());
455
 
  translation->BeginFrame(environment->ast_id(), closure_id, height);
 
482
  if (environment->is_arguments_adaptor()) {
 
483
    translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
 
484
  } else {
 
485
    translation->BeginJSFrame(environment->ast_id(), closure_id, height);
 
486
  }
456
487
  for (int i = 0; i < translation_size; ++i) {
457
488
    LOperand* value = environment->values()->at(i);
458
489
    // spilled_registers_ and spilled_double_registers_ are either
585
616
    // |>------------  translation_size ------------<|
586
617
 
587
618
    int frame_count = 0;
 
619
    int jsframe_count = 0;
588
620
    for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
589
621
      ++frame_count;
 
622
      if (!e->is_arguments_adaptor()) {
 
623
        ++jsframe_count;
 
624
      }
590
625
    }
591
 
    Translation translation(&translations_, frame_count);
 
626
    Translation translation(&translations_, frame_count, jsframe_count);
592
627
    WriteTranslation(environment, &translation);
593
628
    int deoptimization_index = deoptimizations_.length();
594
629
    int pc_offset = masm()->pc_offset();
1337
1372
 
1338
1373
 
1339
1374
void LCodeGen::DoConstantT(LConstantT* instr) {
1340
 
  ASSERT(instr->result()->IsRegister());
1341
 
  __ mov(ToRegister(instr->result()), Operand(instr->value()));
 
1375
  Handle<Object> value = instr->value();
 
1376
  if (value->IsSmi()) {
 
1377
    __ mov(ToRegister(instr->result()), Operand(value));
 
1378
  } else {
 
1379
    __ LoadHeapObject(ToRegister(instr->result()),
 
1380
                      Handle<HeapObject>::cast(value));
 
1381
  }
1342
1382
}
1343
1383
 
1344
1384
 
1962
2002
 
1963
2003
 
1964
2004
// Branches to a label or falls through with the answer in flags.  Trashes
1965
 
// the temp registers, but not the input.  Only input and temp2 may alias.
 
2005
// the temp registers, but not the input.
1966
2006
void LCodeGen::EmitClassOfTest(Label* is_true,
1967
2007
                               Label* is_false,
1968
2008
                               Handle<String>class_name,
1970
2010
                               Register temp,
1971
2011
                               Register temp2) {
1972
2012
  ASSERT(!input.is(temp));
1973
 
  ASSERT(!temp.is(temp2));  // But input and temp2 may be the same register.
 
2013
  ASSERT(!input.is(temp2));
 
2014
  ASSERT(!temp.is(temp2));
 
2015
 
1974
2016
  __ JumpIfSmi(input, is_false);
1975
2017
 
1976
2018
  if (class_name->IsEqualTo(CStrVector("Function"))) {
2167
2209
  // offset to the location of the map check.
2168
2210
  Register temp = ToRegister(instr->TempAt(0));
2169
2211
  ASSERT(temp.is(r4));
2170
 
  __ mov(InstanceofStub::right(), Operand(instr->function()));
 
2212
  __ LoadHeapObject(InstanceofStub::right(), instr->function());
2171
2213
  static const int kAdditionalDelta = 4;
2172
2214
  int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta;
2173
2215
  Label before_push_delta;
2245
2287
 
2246
2288
 
2247
2289
void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
2248
 
  Register value = ToRegister(instr->InputAt(0));
2249
 
  Register scratch = scratch0();
2250
 
  Register scratch2 = ToRegister(instr->TempAt(0));
 
2290
  Register value = ToRegister(instr->value());
 
2291
  Register cell = scratch0();
2251
2292
 
2252
2293
  // Load the cell.
2253
 
  __ mov(scratch, Operand(Handle<Object>(instr->hydrogen()->cell())));
 
2294
  __ mov(cell, Operand(instr->hydrogen()->cell()));
2254
2295
 
2255
2296
  // If the cell we are storing to contains the hole it could have
2256
2297
  // been deleted from the property dictionary. In that case, we need
2257
2298
  // to update the property details in the property dictionary to mark
2258
2299
  // it as no longer deleted.
2259
2300
  if (instr->hydrogen()->RequiresHoleCheck()) {
2260
 
    __ ldr(scratch2,
2261
 
           FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
2262
 
    __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
2263
 
    __ cmp(scratch2, ip);
 
2301
    // We use a temp to check the payload (CompareRoot might clobber ip).
 
2302
    Register payload = ToRegister(instr->TempAt(0));
 
2303
    __ ldr(payload, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset));
 
2304
    __ CompareRoot(payload, Heap::kTheHoleValueRootIndex);
2264
2305
    DeoptimizeIf(eq, instr->environment());
2265
2306
  }
2266
2307
 
2267
2308
  // Store the value.
2268
 
  __ str(value, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
 
2309
  __ str(value, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset));
2269
2310
  // Cells are always rescanned, so no write barrier here.
2270
2311
}
2271
2312
 
2286
2327
  Register context = ToRegister(instr->context());
2287
2328
  Register result = ToRegister(instr->result());
2288
2329
  __ ldr(result, ContextOperand(context, instr->slot_index()));
 
2330
  if (instr->hydrogen()->RequiresHoleCheck()) {
 
2331
    __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
 
2332
    __ cmp(result, ip);
 
2333
    if (instr->hydrogen()->DeoptimizesOnHole()) {
 
2334
      DeoptimizeIf(eq, instr->environment());
 
2335
    } else {
 
2336
      __ mov(result, Operand(factory()->undefined_value()), LeaveCC, eq);
 
2337
    }
 
2338
  }
2289
2339
}
2290
2340
 
2291
2341
 
2292
2342
void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2293
2343
  Register context = ToRegister(instr->context());
2294
2344
  Register value = ToRegister(instr->value());
 
2345
  Register scratch = scratch0();
2295
2346
  MemOperand target = ContextOperand(context, instr->slot_index());
 
2347
 
 
2348
  Label skip_assignment;
 
2349
 
 
2350
  if (instr->hydrogen()->RequiresHoleCheck()) {
 
2351
    __ ldr(scratch, target);
 
2352
    __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
 
2353
    __ cmp(scratch, ip);
 
2354
    if (instr->hydrogen()->DeoptimizesOnHole()) {
 
2355
      DeoptimizeIf(eq, instr->environment());
 
2356
    } else {
 
2357
      __ b(ne, &skip_assignment);
 
2358
    }
 
2359
  }
 
2360
 
2296
2361
  __ str(value, target);
2297
2362
  if (instr->hydrogen()->NeedsWriteBarrier()) {
2298
2363
    HType type = instr->hydrogen()->value()->type();
2301
2366
    __ RecordWriteContextSlot(context,
2302
2367
                              target.offset(),
2303
2368
                              value,
2304
 
                              scratch0(),
 
2369
                              scratch,
2305
2370
                              kLRHasBeenSaved,
2306
2371
                              kSaveFPRegs,
2307
2372
                              EMIT_REMEMBERED_SET,
2308
2373
                              check_needed);
2309
2374
  }
 
2375
 
 
2376
  __ bind(&skip_assignment);
2310
2377
}
2311
2378
 
2312
2379
 
2328
2395
                                               Handle<String> name) {
2329
2396
  LookupResult lookup(isolate());
2330
2397
  type->LookupInDescriptors(NULL, *name, &lookup);
2331
 
  ASSERT(lookup.IsProperty() &&
 
2398
  ASSERT(lookup.IsFound() &&
2332
2399
         (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
2333
2400
  if (lookup.type() == FIELD) {
2334
2401
    int index = lookup.GetLocalFieldIndexFromMap(*type);
2344
2411
    }
2345
2412
  } else {
2346
2413
    Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
2347
 
    LoadHeapObject(result, Handle<HeapObject>::cast(function));
 
2414
    __ LoadHeapObject(result, function);
2348
2415
  }
2349
2416
}
2350
2417
 
2769
2836
      this, pointers, Safepoint::kLazyDeopt);
2770
2837
  // The number of arguments is stored in receiver which is r0, as expected
2771
2838
  // by InvokeFunction.
2772
 
  v8::internal::ParameterCount actual(receiver);
 
2839
  ParameterCount actual(receiver);
2773
2840
  __ InvokeFunction(function, actual, CALL_FUNCTION,
2774
2841
                    safepoint_generator, CALL_AS_METHOD);
2775
2842
  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2789
2856
 
2790
2857
void LCodeGen::DoThisFunction(LThisFunction* instr) {
2791
2858
  Register result = ToRegister(instr->result());
2792
 
  LoadHeapObject(result, instr->hydrogen()->closure());
 
2859
  __ LoadHeapObject(result, instr->hydrogen()->closure());
2793
2860
}
2794
2861
 
2795
2862
 
2824
2891
                                 int arity,
2825
2892
                                 LInstruction* instr,
2826
2893
                                 CallKind call_kind) {
2827
 
  // Change context if needed.
2828
 
  bool change_context =
2829
 
      (info()->closure()->context() != function->context()) ||
2830
 
      scope()->contains_with() ||
2831
 
      (scope()->num_heap_slots() > 0);
2832
 
  if (change_context) {
2833
 
    __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
2834
 
  }
2835
 
 
2836
 
  // Set r0 to arguments count if adaption is not needed. Assumes that r0
2837
 
  // is available to write to at this point.
2838
 
  if (!function->NeedsArgumentsAdaption()) {
2839
 
    __ mov(r0, Operand(arity));
2840
 
  }
 
2894
  bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
 
2895
      function->shared()->formal_parameter_count() == arity;
2841
2896
 
2842
2897
  LPointerMap* pointers = instr->pointer_map();
2843
2898
  RecordPosition(pointers->position());
2844
2899
 
2845
 
  // Invoke function.
2846
 
  __ SetCallKind(r5, call_kind);
2847
 
  __ ldr(ip, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
2848
 
  __ Call(ip);
2849
 
 
2850
 
  // Setup deoptimization.
2851
 
  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
 
2900
  if (can_invoke_directly) {
 
2901
    __ LoadHeapObject(r1, function);
 
2902
    // Change context if needed.
 
2903
    bool change_context =
 
2904
        (info()->closure()->context() != function->context()) ||
 
2905
        scope()->contains_with() ||
 
2906
        (scope()->num_heap_slots() > 0);
 
2907
    if (change_context) {
 
2908
      __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
 
2909
    }
 
2910
 
 
2911
    // Set r0 to arguments count if adaption is not needed. Assumes that r0
 
2912
    // is available to write to at this point.
 
2913
    if (!function->NeedsArgumentsAdaption()) {
 
2914
      __ mov(r0, Operand(arity));
 
2915
    }
 
2916
 
 
2917
    // Invoke function.
 
2918
    __ SetCallKind(r5, call_kind);
 
2919
    __ ldr(ip, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
 
2920
    __ Call(ip);
 
2921
 
 
2922
    // Set up deoptimization.
 
2923
    RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
 
2924
  } else {
 
2925
    SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
 
2926
    ParameterCount count(arity);
 
2927
    __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
 
2928
  }
2852
2929
 
2853
2930
  // Restore context.
2854
2931
  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2857
2934
 
2858
2935
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
2859
2936
  ASSERT(ToRegister(instr->result()).is(r0));
2860
 
  __ mov(r1, Operand(instr->function()));
2861
2937
  CallKnownFunction(instr->function(),
2862
2938
                    instr->arity(),
2863
2939
                    instr,
3086
3162
void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
3087
3163
  DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
3088
3164
  DoubleRegister result = ToDoubleRegister(instr->result());
 
3165
  DoubleRegister temp = ToDoubleRegister(instr->TempAt(0));
 
3166
 
 
3167
  // Note that according to ECMA-262 15.8.2.13:
 
3168
  // Math.pow(-Infinity, 0.5) == Infinity
 
3169
  // Math.sqrt(-Infinity) == NaN
 
3170
  Label done;
 
3171
  __ vmov(temp, -V8_INFINITY);
 
3172
  __ VFPCompareAndSetFlags(input, temp);
 
3173
  __ vneg(result, temp, eq);
 
3174
  __ b(&done, eq);
 
3175
 
3089
3176
  // Add +0 to convert -0 to +0.
3090
3177
  __ vadd(result, input, kDoubleRegZero);
3091
3178
  __ vsqrt(result, result);
 
3179
  __ bind(&done);
3092
3180
}
3093
3181
 
3094
3182
 
3095
3183
void LCodeGen::DoPower(LPower* instr) {
3096
 
  LOperand* left = instr->InputAt(0);
3097
 
  LOperand* right = instr->InputAt(1);
3098
 
  Register scratch = scratch0();
3099
 
  DoubleRegister result_reg = ToDoubleRegister(instr->result());
3100
3184
  Representation exponent_type = instr->hydrogen()->right()->representation();
3101
 
  if (exponent_type.IsDouble()) {
3102
 
    // Prepare arguments and call C function.
3103
 
    __ PrepareCallCFunction(0, 2, scratch);
3104
 
    __ SetCallCDoubleArguments(ToDoubleRegister(left),
3105
 
                               ToDoubleRegister(right));
3106
 
    __ CallCFunction(
3107
 
        ExternalReference::power_double_double_function(isolate()), 0, 2);
 
3185
  // Having marked this as a call, we can use any registers.
 
3186
  // Just make sure that the input/output registers are the expected ones.
 
3187
  ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
 
3188
         ToDoubleRegister(instr->InputAt(1)).is(d2));
 
3189
  ASSERT(!instr->InputAt(1)->IsRegister() ||
 
3190
         ToRegister(instr->InputAt(1)).is(r2));
 
3191
  ASSERT(ToDoubleRegister(instr->InputAt(0)).is(d1));
 
3192
  ASSERT(ToDoubleRegister(instr->result()).is(d3));
 
3193
 
 
3194
  if (exponent_type.IsTagged()) {
 
3195
    Label no_deopt;
 
3196
    __ JumpIfSmi(r2, &no_deopt);
 
3197
    __ ldr(r7, FieldMemOperand(r2, HeapObject::kMapOffset));
 
3198
    __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
 
3199
    __ cmp(r7, Operand(ip));
 
3200
    DeoptimizeIf(ne, instr->environment());
 
3201
    __ bind(&no_deopt);
 
3202
    MathPowStub stub(MathPowStub::TAGGED);
 
3203
    __ CallStub(&stub);
3108
3204
  } else if (exponent_type.IsInteger32()) {
3109
 
    ASSERT(ToRegister(right).is(r0));
3110
 
    // Prepare arguments and call C function.
3111
 
    __ PrepareCallCFunction(1, 1, scratch);
3112
 
    __ SetCallCDoubleArguments(ToDoubleRegister(left), ToRegister(right));
3113
 
    __ CallCFunction(
3114
 
        ExternalReference::power_double_int_function(isolate()), 1, 1);
 
3205
    MathPowStub stub(MathPowStub::INTEGER);
 
3206
    __ CallStub(&stub);
3115
3207
  } else {
3116
 
    ASSERT(exponent_type.IsTagged());
3117
 
    ASSERT(instr->hydrogen()->left()->representation().IsDouble());
3118
 
 
3119
 
    Register right_reg = ToRegister(right);
3120
 
 
3121
 
    // Check for smi on the right hand side.
3122
 
    Label non_smi, call;
3123
 
    __ JumpIfNotSmi(right_reg, &non_smi);
3124
 
 
3125
 
    // Untag smi and convert it to a double.
3126
 
    __ SmiUntag(right_reg);
3127
 
    SwVfpRegister single_scratch = double_scratch0().low();
3128
 
    __ vmov(single_scratch, right_reg);
3129
 
    __ vcvt_f64_s32(result_reg, single_scratch);
3130
 
    __ jmp(&call);
3131
 
 
3132
 
    // Heap number map check.
3133
 
    __ bind(&non_smi);
3134
 
    __ ldr(scratch, FieldMemOperand(right_reg, HeapObject::kMapOffset));
3135
 
    __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
3136
 
    __ cmp(scratch, Operand(ip));
3137
 
    DeoptimizeIf(ne, instr->environment());
3138
 
    int32_t value_offset = HeapNumber::kValueOffset - kHeapObjectTag;
3139
 
    __ add(scratch, right_reg, Operand(value_offset));
3140
 
    __ vldr(result_reg, scratch, 0);
3141
 
 
3142
 
    // Prepare arguments and call C function.
3143
 
    __ bind(&call);
3144
 
    __ PrepareCallCFunction(0, 2, scratch);
3145
 
    __ SetCallCDoubleArguments(ToDoubleRegister(left), result_reg);
3146
 
    __ CallCFunction(
3147
 
        ExternalReference::power_double_double_function(isolate()), 0, 2);
 
3208
    ASSERT(exponent_type.IsDouble());
 
3209
    MathPowStub stub(MathPowStub::DOUBLE);
 
3210
    __ CallStub(&stub);
3148
3211
  }
3149
 
  // Store the result in the result register.
3150
 
  __ GetCFunctionDoubleResult(result_reg);
 
3212
}
 
3213
 
 
3214
 
 
3215
void LCodeGen::DoRandom(LRandom* instr) {
 
3216
  // Having marked this instruction as a call we can use any
 
3217
  // registers.
 
3218
  ASSERT(ToDoubleRegister(instr->result()).is(d7));
 
3219
  ASSERT(ToRegister(instr->InputAt(0)).is(r0));
 
3220
 
 
3221
  __ PrepareCallCFunction(1, scratch0());
 
3222
  __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalContextOffset));
 
3223
  __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
 
3224
 
 
3225
  // 0x41300000 is the top half of 1.0 x 2^20 as a double.
 
3226
  // Create this constant using mov/orr to avoid PC relative load.
 
3227
  __ mov(r1, Operand(0x41000000));
 
3228
  __ orr(r1, r1, Operand(0x300000));
 
3229
  // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
 
3230
  __ vmov(d7, r0, r1);
 
3231
  // Move 0x4130000000000000 to VFP.
 
3232
  __ mov(r0, Operand(0, RelocInfo::NONE));
 
3233
  __ vmov(d8, r0, r1);
 
3234
  // Subtract and store the result in the heap number.
 
3235
  __ vsub(d7, d7, d8);
3151
3236
}
3152
3237
 
3153
3238
 
3283
3368
 
3284
3369
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
3285
3370
  ASSERT(ToRegister(instr->result()).is(r0));
3286
 
  __ mov(r1, Operand(instr->target()));
3287
3371
  CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
3288
3372
}
3289
3373
 
3377
3461
  Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
3378
3462
  Register scratch = scratch0();
3379
3463
 
3380
 
  // This instruction cannot handle the FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
3381
 
  // conversion, so it deopts in that case.
3382
 
  if (instr->hydrogen()->ValueNeedsSmiCheck()) {
3383
 
    __ tst(value, Operand(kSmiTagMask));
3384
 
    DeoptimizeIf(ne, instr->environment());
3385
 
  }
3386
 
 
3387
3464
  // Do the store.
3388
3465
  if (instr->key()->IsConstantOperand()) {
3389
3466
    ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
3842
3919
void LCodeGen::EmitNumberUntagD(Register input_reg,
3843
3920
                                DoubleRegister result_reg,
3844
3921
                                bool deoptimize_on_undefined,
 
3922
                                bool deoptimize_on_minus_zero,
3845
3923
                                LEnvironment* env) {
3846
3924
  Register scratch = scratch0();
3847
3925
  SwVfpRegister flt_scratch = double_scratch0().low();
3877
3955
  // Heap number to double register conversion.
3878
3956
  __ sub(ip, input_reg, Operand(kHeapObjectTag));
3879
3957
  __ vldr(result_reg, ip, HeapNumber::kValueOffset);
 
3958
  if (deoptimize_on_minus_zero) {
 
3959
    __ vmov(ip, result_reg.low());
 
3960
    __ cmp(ip, Operand(0));
 
3961
    __ b(ne, &done);
 
3962
    __ vmov(ip, result_reg.high());
 
3963
    __ cmp(ip, Operand(HeapNumber::kSignMask));
 
3964
    DeoptimizeIf(eq, env);
 
3965
  }
3880
3966
  __ jmp(&done);
3881
3967
 
3882
3968
  // Smi to double register conversion
4010
4096
 
4011
4097
  EmitNumberUntagD(input_reg, result_reg,
4012
4098
                   instr->hydrogen()->deoptimize_on_undefined(),
 
4099
                   instr->hydrogen()->deoptimize_on_minus_zero(),
4013
4100
                   instr->environment());
4014
4101
}
4015
4102
 
4107
4194
 
4108
4195
 
4109
4196
void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
4110
 
  ASSERT(instr->InputAt(0)->IsRegister());
4111
 
  Register reg = ToRegister(instr->InputAt(0));
4112
 
  __ cmp(reg, Operand(instr->hydrogen()->target()));
 
4197
  Register reg = ToRegister(instr->value());
 
4198
  Handle<JSFunction> target = instr->hydrogen()->target();
 
4199
  if (isolate()->heap()->InNewSpace(*target)) {
 
4200
    Register reg = ToRegister(instr->value());
 
4201
    Handle<JSGlobalPropertyCell> cell =
 
4202
        isolate()->factory()->NewJSGlobalPropertyCell(target);
 
4203
    __ mov(ip, Operand(Handle<Object>(cell)));
 
4204
    __ ldr(ip, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset));
 
4205
    __ cmp(reg, ip);
 
4206
  } else {
 
4207
    __ cmp(reg, Operand(target));
 
4208
  }
4113
4209
  DeoptimizeIf(ne, instr->environment());
4114
4210
}
4115
4211
 
4116
4212
 
 
4213
void LCodeGen::DoCheckMapCommon(Register reg,
 
4214
                                Register scratch,
 
4215
                                Handle<Map> map,
 
4216
                                CompareMapMode mode,
 
4217
                                LEnvironment* env) {
 
4218
  Label success;
 
4219
  __ CompareMap(reg, scratch, map, &success, mode);
 
4220
  DeoptimizeIf(ne, env);
 
4221
  __ bind(&success);
 
4222
}
 
4223
 
 
4224
 
4117
4225
void LCodeGen::DoCheckMap(LCheckMap* instr) {
4118
4226
  Register scratch = scratch0();
4119
4227
  LOperand* input = instr->InputAt(0);
4120
4228
  ASSERT(input->IsRegister());
4121
4229
  Register reg = ToRegister(input);
4122
 
  __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
4123
 
  __ cmp(scratch, Operand(instr->hydrogen()->map()));
4124
 
  DeoptimizeIf(ne, instr->environment());
 
4230
  Handle<Map> map = instr->hydrogen()->map();
 
4231
  DoCheckMapCommon(reg, scratch, map, instr->hydrogen()->mode(),
 
4232
                   instr->environment());
4125
4233
}
4126
4234
 
4127
4235
 
4178
4286
}
4179
4287
 
4180
4288
 
4181
 
void LCodeGen::LoadHeapObject(Register result,
4182
 
                              Handle<HeapObject> object) {
4183
 
  if (heap()->InNewSpace(*object)) {
4184
 
    Handle<JSGlobalPropertyCell> cell =
4185
 
        factory()->NewJSGlobalPropertyCell(object);
4186
 
    __ mov(result, Operand(cell));
4187
 
    __ ldr(result, FieldMemOperand(result, JSGlobalPropertyCell::kValueOffset));
4188
 
  } else {
4189
 
    __ mov(result, Operand(object));
4190
 
  }
4191
 
}
4192
 
 
4193
 
 
4194
4289
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
4195
4290
  Register temp1 = ToRegister(instr->TempAt(0));
4196
4291
  Register temp2 = ToRegister(instr->TempAt(1));
4199
4294
  Handle<JSObject> current_prototype = instr->prototype();
4200
4295
 
4201
4296
  // Load prototype object.
4202
 
  LoadHeapObject(temp1, current_prototype);
 
4297
  __ LoadHeapObject(temp1, current_prototype);
4203
4298
 
4204
4299
  // Check prototype maps up to the holder.
4205
4300
  while (!current_prototype.is_identical_to(holder)) {
4206
 
    __ ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset));
4207
 
    __ cmp(temp2, Operand(Handle<Map>(current_prototype->map())));
4208
 
    DeoptimizeIf(ne, instr->environment());
 
4301
    DoCheckMapCommon(temp1, temp2,
 
4302
                     Handle<Map>(current_prototype->map()),
 
4303
                     ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
4209
4304
    current_prototype =
4210
4305
        Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
4211
4306
    // Load next prototype object.
4212
 
    LoadHeapObject(temp1, current_prototype);
 
4307
    __ LoadHeapObject(temp1, current_prototype);
4213
4308
  }
4214
4309
 
4215
4310
  // Check the holder map.
4216
 
  __ ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset));
4217
 
  __ cmp(temp2, Operand(Handle<Map>(current_prototype->map())));
 
4311
  DoCheckMapCommon(temp1, temp2,
 
4312
                   Handle<Map>(current_prototype->map()),
 
4313
                   ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
4218
4314
  DeoptimizeIf(ne, instr->environment());
4219
4315
}
4220
4316
 
4221
4317
 
4222
4318
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
4223
 
  Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements();
4224
 
  ASSERT_EQ(2, constant_elements->length());
4225
 
  ElementsKind constant_elements_kind =
4226
 
      static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
 
4319
  Heap* heap = isolate()->heap();
 
4320
  ElementsKind boilerplate_elements_kind =
 
4321
      instr->hydrogen()->boilerplate_elements_kind();
 
4322
 
 
4323
  // Deopt if the array literal boilerplate ElementsKind is of a type different
 
4324
  // than the expected one. The check isn't necessary if the boilerplate has
 
4325
  // already been converted to FAST_ELEMENTS.
 
4326
  if (boilerplate_elements_kind != FAST_ELEMENTS) {
 
4327
    __ LoadHeapObject(r1, instr->hydrogen()->boilerplate_object());
 
4328
    // Load map into r2.
 
4329
    __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
 
4330
    // Load the map's "bit field 2".
 
4331
    __ ldrb(r2, FieldMemOperand(r2, Map::kBitField2Offset));
 
4332
    // Retrieve elements_kind from bit field 2.
 
4333
    __ ubfx(r2, r2, Map::kElementsKindShift, Map::kElementsKindBitCount);
 
4334
    __ cmp(r2, Operand(boilerplate_elements_kind));
 
4335
    DeoptimizeIf(ne, instr->environment());
 
4336
  }
4227
4337
 
4228
4338
  __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
4229
4339
  __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
4230
4340
  __ mov(r2, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
4231
 
  __ mov(r1, Operand(constant_elements));
 
4341
  // Boilerplate already exists, constant elements are never accessed.
 
4342
  // Pass an empty fixed array.
 
4343
  __ mov(r1, Operand(Handle<FixedArray>(heap->empty_fixed_array())));
4232
4344
  __ Push(r3, r2, r1);
4233
4345
 
4234
4346
  // Pick the right runtime function or stub to call.
4245
4357
    CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
4246
4358
  } else {
4247
4359
    FastCloneShallowArrayStub::Mode mode =
4248
 
        constant_elements_kind == FAST_DOUBLE_ELEMENTS
4249
 
        ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
4250
 
        : FastCloneShallowArrayStub::CLONE_ELEMENTS;
 
4360
        boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
 
4361
            ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
 
4362
            : FastCloneShallowArrayStub::CLONE_ELEMENTS;
4251
4363
    FastCloneShallowArrayStub stub(mode, length);
4252
4364
    CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
4253
4365
  }
4286
4398
      Handle<JSObject> value_object = Handle<JSObject>::cast(value);
4287
4399
      __ add(r2, result, Operand(*offset));
4288
4400
      __ str(r2, FieldMemOperand(result, total_offset));
4289
 
      LoadHeapObject(source, value_object);
 
4401
      __ LoadHeapObject(source, value_object);
4290
4402
      EmitDeepCopy(value_object, result, source, offset);
4291
4403
    } else if (value->IsHeapObject()) {
4292
 
      LoadHeapObject(r2, Handle<HeapObject>::cast(value));
 
4404
      __ LoadHeapObject(r2, Handle<HeapObject>::cast(value));
4293
4405
      __ str(r2, FieldMemOperand(result, total_offset));
4294
4406
    } else {
4295
4407
      __ mov(r2, Operand(value));
4315
4427
 
4316
4428
  __ bind(&allocated);
4317
4429
  int offset = 0;
4318
 
  LoadHeapObject(r1, instr->hydrogen()->boilerplate());
 
4430
  __ LoadHeapObject(r1, instr->hydrogen()->boilerplate());
4319
4431
  EmitDeepCopy(instr->hydrogen()->boilerplate(), r0, r1, &offset);
4320
4432
  ASSERT_EQ(size, offset);
4321
4433
}