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();
2252
2293
// Load the cell.
2253
__ mov(scratch, Operand(Handle<Object>(instr->hydrogen()->cell())));
2294
__ mov(cell, Operand(instr->hydrogen()->cell()));
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()) {
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());
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.
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);
2333
if (instr->hydrogen()->DeoptimizesOnHole()) {
2334
DeoptimizeIf(eq, instr->environment());
2336
__ mov(result, Operand(factory()->undefined_value()), LeaveCC, eq);
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());
2348
Label skip_assignment;
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());
2357
__ b(ne, &skip_assignment);
2296
2361
__ str(value, target);
2297
2362
if (instr->hydrogen()->NeedsWriteBarrier()) {
2298
2363
HType type = instr->hydrogen()->value()->type();
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));
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));
2894
bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
2895
function->shared()->formal_parameter_count() == arity;
2842
2897
LPointerMap* pointers = instr->pointer_map();
2843
2898
RecordPosition(pointers->position());
2846
__ SetCallKind(r5, call_kind);
2847
__ ldr(ip, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
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));
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));
2918
__ SetCallKind(r5, call_kind);
2919
__ ldr(ip, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
2922
// Set up deoptimization.
2923
RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
2925
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
2926
ParameterCount count(arity);
2927
__ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
2853
2930
// Restore context.
2854
2931
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
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));
3167
// Note that according to ECMA-262 15.8.2.13:
3168
// Math.pow(-Infinity, 0.5) == Infinity
3169
// Math.sqrt(-Infinity) == NaN
3171
__ vmov(temp, -V8_INFINITY);
3172
__ VFPCompareAndSetFlags(input, temp);
3173
__ vneg(result, temp, eq);
3089
3176
// Add +0 to convert -0 to +0.
3090
3177
__ vadd(result, input, kDoubleRegZero);
3091
3178
__ vsqrt(result, result);
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));
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));
3194
if (exponent_type.IsTagged()) {
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());
3202
MathPowStub stub(MathPowStub::TAGGED);
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));
3114
ExternalReference::power_double_int_function(isolate()), 1, 1);
3205
MathPowStub stub(MathPowStub::INTEGER);
3116
ASSERT(exponent_type.IsTagged());
3117
ASSERT(instr->hydrogen()->left()->representation().IsDouble());
3119
Register right_reg = ToRegister(right);
3121
// Check for smi on the right hand side.
3122
Label non_smi, call;
3123
__ JumpIfNotSmi(right_reg, &non_smi);
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);
3132
// Heap number map check.
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);
3142
// Prepare arguments and call C function.
3144
__ PrepareCallCFunction(0, 2, scratch);
3145
__ SetCallCDoubleArguments(ToDoubleRegister(left), result_reg);
3147
ExternalReference::power_double_double_function(isolate()), 0, 2);
3208
ASSERT(exponent_type.IsDouble());
3209
MathPowStub stub(MathPowStub::DOUBLE);
3149
// Store the result in the result register.
3150
__ GetCFunctionDoubleResult(result_reg);
3215
void LCodeGen::DoRandom(LRandom* instr) {
3216
// Having marked this instruction as a call we can use any
3218
ASSERT(ToDoubleRegister(instr->result()).is(d7));
3219
ASSERT(ToRegister(instr->InputAt(0)).is(r0));
3221
__ PrepareCallCFunction(1, scratch0());
3222
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalContextOffset));
3223
__ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
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);
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));
4207
__ cmp(reg, Operand(target));
4113
4209
DeoptimizeIf(ne, instr->environment());
4213
void LCodeGen::DoCheckMapCommon(Register reg,
4216
CompareMapMode mode,
4217
LEnvironment* env) {
4219
__ CompareMap(reg, scratch, map, &success, mode);
4220
DeoptimizeIf(ne, env);
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());
4199
4294
Handle<JSObject> current_prototype = instr->prototype();
4201
4296
// Load prototype object.
4202
LoadHeapObject(temp1, current_prototype);
4297
__ LoadHeapObject(temp1, current_prototype);
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);
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());
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();
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());
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);
4234
4346
// Pick the right runtime function or stub to call.