| Index: src/arm/full-codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/full-codegen-arm.cc (revision 6946)
|
| +++ src/arm/full-codegen-arm.cc (working copy)
|
| @@ -574,13 +574,28 @@
|
| void FullCodeGenerator::DoTest(Label* if_true,
|
| Label* if_false,
|
| Label* fall_through) {
|
| - // Call the runtime to find the boolean value of the source and then
|
| - // translate it into control flow to the pair of labels.
|
| - __ push(result_register());
|
| - __ CallRuntime(Runtime::kToBool, 1);
|
| + // Emit the inlined tests assumed by the stub.
|
| + __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
| + __ cmp(result_register(), ip);
|
| + __ b(eq, if_false);
|
| __ LoadRoot(ip, Heap::kTrueValueRootIndex);
|
| - __ cmp(r0, ip);
|
| - Split(eq, if_true, if_false, fall_through);
|
| + __ cmp(result_register(), ip);
|
| + __ b(eq, if_true);
|
| + __ LoadRoot(ip, Heap::kFalseValueRootIndex);
|
| + __ cmp(result_register(), ip);
|
| + __ b(eq, if_false);
|
| + STATIC_ASSERT(kSmiTag == 0);
|
| + __ tst(result_register(), result_register());
|
| + __ b(eq, if_false);
|
| + __ JumpIfSmi(result_register(), if_true);
|
| +
|
| + // Call the ToBoolean stub for all other cases.
|
| + ToBooleanStub stub(result_register());
|
| + __ CallStub(&stub);
|
| + __ tst(result_register(), result_register());
|
| +
|
| + // The stub returns nonzero for true.
|
| + Split(ne, if_true, if_false, fall_through);
|
| }
|
|
|
|
|
| @@ -796,9 +811,9 @@
|
| Comment cmnt(masm_, "[ SwitchStatement");
|
| Breakable nested_statement(this, stmt);
|
| SetStatementPosition(stmt);
|
| +
|
| // Keep the switch value on the stack until a case matches.
|
| VisitForStackValue(stmt->tag());
|
| -
|
| PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
|
|
|
| ZoneList<CaseClause*>* clauses = stmt->cases();
|
| @@ -1062,8 +1077,14 @@
|
| void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
|
| bool pretenure) {
|
| // Use the fast case closure allocation code that allocates in new
|
| - // space for nested functions that don't need literals cloning.
|
| - if (scope()->is_function_scope() &&
|
| + // space for nested functions that don't need literals cloning. If
|
| + // we're running with the --always-opt or the --prepare-always-opt
|
| + // flag, we need to use the runtime function so that the new function
|
| + // we are creating here gets a chance to have its code optimized and
|
| + // doesn't just get a copy of the existing unoptimized code.
|
| + if (!FLAG_always_opt &&
|
| + !FLAG_prepare_always_opt &&
|
| + scope()->is_function_scope() &&
|
| info->num_literals() == 0 &&
|
| !pretenure) {
|
| FastNewClosureStub stub;
|
| @@ -1317,18 +1338,19 @@
|
| Comment cmnt(masm_, "[ RegExpLiteral");
|
| Label materialized;
|
| // Registers will be used as follows:
|
| + // r5 = materialized value (RegExp literal)
|
| // r4 = JS function, literals array
|
| // r3 = literal index
|
| // r2 = RegExp pattern
|
| // r1 = RegExp flags
|
| - // r0 = temp + materialized value (RegExp literal)
|
| + // r0 = RegExp literal clone
|
| __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
| __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
|
| int literal_offset =
|
| FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
|
| - __ ldr(r0, FieldMemOperand(r4, literal_offset));
|
| + __ ldr(r5, FieldMemOperand(r4, literal_offset));
|
| __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
| - __ cmp(r0, ip);
|
| + __ cmp(r5, ip);
|
| __ b(ne, &materialized);
|
|
|
| // Create regexp literal using runtime function.
|
| @@ -1338,20 +1360,27 @@
|
| __ mov(r1, Operand(expr->flags()));
|
| __ Push(r4, r3, r2, r1);
|
| __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
|
| + __ mov(r5, r0);
|
|
|
| __ bind(&materialized);
|
| int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
|
| - __ push(r0);
|
| + Label allocated, runtime_allocate;
|
| + __ AllocateInNewSpace(size, r0, r2, r3, &runtime_allocate, TAG_OBJECT);
|
| + __ jmp(&allocated);
|
| +
|
| + __ bind(&runtime_allocate);
|
| + __ push(r5);
|
| __ mov(r0, Operand(Smi::FromInt(size)));
|
| __ push(r0);
|
| __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
|
| + __ pop(r5);
|
|
|
| + __ bind(&allocated);
|
| // After this, registers are used as follows:
|
| // r0: Newly allocated regexp.
|
| - // r1: Materialized regexp.
|
| + // r5: Materialized regexp.
|
| // r2: temp.
|
| - __ pop(r1);
|
| - __ CopyFields(r0, r1, r2.bit(), size / kPointerSize);
|
| + __ CopyFields(r0, r5, r2.bit(), size / kPointerSize);
|
| context()->Plug(r0);
|
| }
|
|
|
| @@ -3186,37 +3215,40 @@
|
|
|
|
|
| void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
|
| - // Load the argument on the stack and call the runtime.
|
| + // Load the argument on the stack and call the stub.
|
| + TranscendentalCacheStub stub(TranscendentalCache::SIN);
|
| ASSERT(args->length() == 1);
|
| VisitForStackValue(args->at(0));
|
| - __ CallRuntime(Runtime::kMath_sin, 1);
|
| + __ CallStub(&stub);
|
| context()->Plug(r0);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
|
| - // Load the argument on the stack and call the runtime.
|
| + // Load the argument on the stack and call the stub.
|
| + TranscendentalCacheStub stub(TranscendentalCache::COS);
|
| ASSERT(args->length() == 1);
|
| VisitForStackValue(args->at(0));
|
| - __ CallRuntime(Runtime::kMath_cos, 1);
|
| + __ CallStub(&stub);
|
| context()->Plug(r0);
|
| }
|
|
|
|
|
| -void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
|
| - // Load the argument on the stack and call the runtime function.
|
| +void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
|
| + // Load the argument on the stack and call the stub.
|
| + TranscendentalCacheStub stub(TranscendentalCache::LOG);
|
| ASSERT(args->length() == 1);
|
| VisitForStackValue(args->at(0));
|
| - __ CallRuntime(Runtime::kMath_sqrt, 1);
|
| + __ CallStub(&stub);
|
| context()->Plug(r0);
|
| }
|
|
|
|
|
| -void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
|
| +void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
|
| // Load the argument on the stack and call the runtime function.
|
| ASSERT(args->length() == 1);
|
| VisitForStackValue(args->at(0));
|
| - __ CallRuntime(Runtime::kMath_log, 1);
|
| + __ CallRuntime(Runtime::kMath_sqrt, 1);
|
| context()->Plug(r0);
|
| }
|
|
|
| @@ -3375,8 +3407,14 @@
|
| void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
| VisitForAccumulatorValue(args->at(0));
|
| +
|
| + if (FLAG_debug_code) {
|
| + __ AbortIfNotString(r0);
|
| + }
|
| +
|
| __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
|
| __ IndexFromHash(r0, r0);
|
| +
|
| context()->Plug(r0);
|
| }
|
|
|
| @@ -3538,9 +3576,7 @@
|
| bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
|
| UnaryOverwriteMode overwrite =
|
| can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
|
| - GenericUnaryOpStub stub(Token::SUB,
|
| - overwrite,
|
| - NO_UNARY_FLAGS);
|
| + GenericUnaryOpStub stub(Token::SUB, overwrite, NO_UNARY_FLAGS);
|
| // GenericUnaryOpStub expects the argument to be in the
|
| // accumulator register r0.
|
| VisitForAccumulatorValue(expr->expression());
|
| @@ -4050,11 +4086,43 @@
|
| void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
|
| ASSERT(mode == RelocInfo::CODE_TARGET ||
|
| mode == RelocInfo::CODE_TARGET_CONTEXT);
|
| + switch (ic->kind()) {
|
| + case Code::LOAD_IC:
|
| + __ IncrementCounter(&Counters::named_load_full, 1, r1, r2);
|
| + break;
|
| + case Code::KEYED_LOAD_IC:
|
| + __ IncrementCounter(&Counters::keyed_load_full, 1, r1, r2);
|
| + break;
|
| + case Code::STORE_IC:
|
| + __ IncrementCounter(&Counters::named_store_full, 1, r1, r2);
|
| + break;
|
| + case Code::KEYED_STORE_IC:
|
| + __ IncrementCounter(&Counters::keyed_store_full, 1, r1, r2);
|
| + default:
|
| + break;
|
| + }
|
| +
|
| __ Call(ic, mode);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
|
| + switch (ic->kind()) {
|
| + case Code::LOAD_IC:
|
| + __ IncrementCounter(&Counters::named_load_full, 1, r1, r2);
|
| + break;
|
| + case Code::KEYED_LOAD_IC:
|
| + __ IncrementCounter(&Counters::keyed_load_full, 1, r1, r2);
|
| + break;
|
| + case Code::STORE_IC:
|
| + __ IncrementCounter(&Counters::named_store_full, 1, r1, r2);
|
| + break;
|
| + case Code::KEYED_STORE_IC:
|
| + __ IncrementCounter(&Counters::keyed_store_full, 1, r1, r2);
|
| + default:
|
| + break;
|
| + }
|
| +
|
| __ Call(ic, RelocInfo::CODE_TARGET);
|
| if (patch_site != NULL && patch_site->is_bound()) {
|
| patch_site->EmitPatchInfo();
|
|
|