📄 codegen-arm.cc.svn-base
字号:
__ push(r0); __ bind(&loaded); cc_reg_ = al; } if (true_target.is_linked() || false_target.is_linked()) { // we have at least one condition value // that has been "translated" into a branch, // thus it needs to be loaded explicitly again Label loaded; __ b(&loaded); // don't lose current TOS bool both = true_target.is_linked() && false_target.is_linked(); // reincarnate "true", if necessary if (true_target.is_linked()) { __ bind(&true_target); __ mov(r0, Operand(Factory::true_value())); __ push(r0); } // if both "true" and "false" need to be reincarnated, // jump across code for "false" if (both) __ b(&loaded); // reincarnate "false", if necessary if (false_target.is_linked()) { __ bind(&false_target); __ mov(r0, Operand(Factory::false_value())); __ push(r0); } // everything is loaded at this point __ bind(&loaded); } ASSERT(!has_cc());}void ArmCodeGenerator::LoadGlobal() { __ ldr(r0, GlobalObject()); __ push(r0);}// TODO(1241834): Get rid of this function in favor of just using Load, now// that we have the LOAD_TYPEOF_EXPR access type. => Need to handle// global variables w/o reference errors elsewhere.void ArmCodeGenerator::LoadTypeofExpression(Expression* x) { Variable* variable = x->AsVariableProxy()->AsVariable(); if (variable != NULL && !variable->is_this() && variable->is_global()) { // NOTE: This is somewhat nasty. We force the compiler to load // the variable as if through '<global>.<variable>' to make sure we // do not get reference errors. Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); Literal key(variable->name()); // TODO(1241834): Fetch the position from the variable instead of using // no position. Property property(&global, &key, RelocInfo::kNoPosition); Load(&property); } else { Load(x, CodeGenState::LOAD_TYPEOF_EXPR); }}Reference::Reference(ArmCodeGenerator* cgen, Expression* expression) : cgen_(cgen), expression_(expression), type_(ILLEGAL) { cgen->LoadReference(this);}Reference::~Reference() { cgen_->UnloadReference(this);}void ArmCodeGenerator::LoadReference(Reference* ref) { Expression* e = ref->expression(); Property* property = e->AsProperty(); Variable* var = e->AsVariableProxy()->AsVariable(); if (property != NULL) { Load(property->obj()); // Used a named reference if the key is a literal symbol. // We don't use a named reference if they key is a string that can be // legally parsed as an integer. This is because, otherwise we don't // get into the slow case code that handles [] on String objects. Literal* literal = property->key()->AsLiteral(); uint32_t dummy; if (literal != NULL && literal->handle()->IsSymbol() && !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { ref->set_type(Reference::NAMED); } else { Load(property->key()); ref->set_type(Reference::KEYED); } } else if (var != NULL) { if (var->is_global()) { // global variable LoadGlobal(); ref->set_type(Reference::NAMED); } else { // local variable ref->set_type(Reference::EMPTY); } } else { Load(e); __ CallRuntime(Runtime::kThrowReferenceError, 1); __ push(r0); }}void ArmCodeGenerator::UnloadReference(Reference* ref) { int size = ref->size(); if (size <= 0) { // Do nothing. No popping is necessary. } else { __ pop(r0); __ add(sp, sp, Operand(size * kPointerSize)); __ push(r0); }}void Property::GenerateStoreCode(MacroAssembler* masm, Scope* scope, Reference* ref, InitState init_state) { Comment cmnt(masm, "[ Store to Property"); masm->RecordPosition(position()); ArmCodeGenerator::SetReferenceProperty(masm, ref, key());}void VariableProxy::GenerateStoreCode(MacroAssembler* masm, Scope* scope, Reference* ref, InitState init_state) { Comment cmnt(masm, "[ Store to VariableProxy"); Variable* node = var(); Expression* expr = node->rewrite(); if (expr != NULL) { expr->GenerateStoreCode(masm, scope, ref, init_state); } else { ASSERT(node->is_global()); if (node->AsProperty() != NULL) { masm->RecordPosition(node->AsProperty()->position()); } ArmCodeGenerator::SetReferenceProperty(masm, ref, new Literal(node->name())); }}void Slot::GenerateStoreCode(MacroAssembler* masm, Scope* scope, Reference* ref, InitState init_state) { Comment cmnt(masm, "[ Store to Slot"); if (type() == Slot::LOOKUP) { ASSERT(var()->mode() == Variable::DYNAMIC); // For now, just do a runtime call. masm->push(cp); masm->mov(r0, Operand(var()->name())); masm->push(r0); if (init_state == CONST_INIT) { // Same as the case for a normal store, but ignores attribute // (e.g. READ_ONLY) of context slot so that we can initialize const // properties (introduced via eval("const foo = (some expr);")). Also, // uses the current function context instead of the top context. // // Note that we must declare the foo upon entry of eval(), via a // context slot declaration, but we cannot initialize it at the same // time, because the const declaration may be at the end of the eval // code (sigh...) and the const variable may have been used before // (where its value is 'undefined'). Thus, we can only do the // initialization when we actually encounter the expression and when // the expression operands are defined and valid, and thus we need the // split into 2 operations: declaration of the context slot followed // by initialization. masm->CallRuntime(Runtime::kInitializeConstContextSlot, 3); } else { masm->CallRuntime(Runtime::kStoreContextSlot, 3); } // Storing a variable must keep the (new) value on the expression // stack. This is necessary for compiling assignment expressions. masm->push(r0); } else { ASSERT(var()->mode() != Variable::DYNAMIC); Label exit; if (init_state == CONST_INIT) { ASSERT(var()->mode() == Variable::CONST); // Only the first const initialization must be executed (the slot // still contains 'the hole' value). When the assignment is executed, // the code is identical to a normal store (see below). Comment cmnt(masm, "[ Init const"); masm->ldr(r2, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); masm->cmp(r2, Operand(Factory::the_hole_value())); masm->b(ne, &exit); } // We must execute the store. // r2 may be loaded with context; used below in RecordWrite. // Storing a variable must keep the (new) value on the stack. This is // necessary for compiling assignment expressions. // // Note: We will reach here even with var()->mode() == Variable::CONST // because of const declarations which will initialize consts to 'the // hole' value and by doing so, end up calling this code. r2 may be // loaded with context; used below in RecordWrite. masm->pop(r0); masm->str(r0, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); masm->push(r0); if (type() == Slot::CONTEXT) { // Skip write barrier if the written value is a smi. masm->tst(r0, Operand(kSmiTagMask)); masm->b(eq, &exit); // r2 is loaded with context when calling SlotOperand above. int offset = FixedArray::kHeaderSize + index() * kPointerSize; masm->mov(r3, Operand(offset)); masm->RecordWrite(r2, r3, r1); } // If we definitely did not jump over the assignment, we do not need to // bind the exit label. Doing so can defeat peephole optimization. if (init_state == CONST_INIT || type() == Slot::CONTEXT) { masm->bind(&exit); } }}// ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given// register to a boolean in the condition code register. The code// may jump to 'false_target' in case the register converts to 'false'.void ArmCodeGenerator::ToBoolean(Label* true_target, Label* false_target) { // Note: The generated code snippet does not change stack variables. // Only the condition code should be set. __ pop(r0); // Fast case checks // Check if the value is 'false'. __ cmp(r0, Operand(Factory::false_value())); __ b(eq, false_target); // Check if the value is 'true'. __ cmp(r0, Operand(Factory::true_value())); __ b(eq, true_target); // Check if the value is 'undefined'. __ cmp(r0, Operand(Factory::undefined_value())); __ b(eq, false_target); // Check if the value is a smi. __ cmp(r0, Operand(Smi::FromInt(0))); __ b(eq, false_target); __ tst(r0, Operand(kSmiTagMask)); __ b(eq, true_target); // Slow case: call the runtime. __ push(r0); __ CallRuntime(Runtime::kToBool, 1); // Convert result (r0) to condition code __ cmp(r0, Operand(Factory::false_value())); cc_reg_ = ne;}#undef __#define __ masm->class GetPropertyStub : public CodeStub { public: GetPropertyStub() { } private: Major MajorKey() { return GetProperty; } int MinorKey() { return 0; } void Generate(MacroAssembler* masm); const char* GetName() { return "GetPropertyStub"; }};void GetPropertyStub::Generate(MacroAssembler* masm) { // sp[0]: key // sp[1]: receiver Label slow, fast; // Get the key and receiver object from the stack. __ ldm(ia, sp, r0.bit() | r1.bit()); // Check that the key is a smi. __ tst(r0, Operand(kSmiTagMask)); __ b(ne, &slow); __ mov(r0, Operand(r0, ASR, kSmiTagSize)); // Check that the object isn't a smi. __ tst(r1, Operand(kSmiTagMask)); __ b(eq, &slow); // Check that the object is some kind of JS object EXCEPT JS Value type. // In the case that the object is a value-wrapper object, // we enter the runtime system to make sure that indexing into string // objects work as intended. ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); __ cmp(r2, Operand(JS_OBJECT_TYPE)); __ b(lt, &slow); // Get the elements array of the object. __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); // Check that the object is in fast mode (not dictionary). __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); __ cmp(r3, Operand(Factory::hash_table_map())); __ b(eq, &slow); // Check that the key (index) is within bounds. __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset)); __ cmp(r0, Operand(r3)); __ b(lo, &fast); // Slow case: Push extra copies of the arguments (2). __ bind(&slow); __ ldm(ia, sp, r0.bit() | r1.bit()); __ stm(db_w, sp, r0.bit() | r1.bit()); // Do tail-call to runtime routine. __ TailCallRuntime(ExternalReference(Runtime::kGetProperty), 2); // Fast case: Do the load. __ bind(&fast); __ add(r3, r1, Operand(Array::kHeaderSize - kHeapObjectTag)); __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2)); __ cmp(r0, Operand(Factory::the_hole_value())); // In case the loaded value is the_hole we have to consult GetProperty // to ensure the prototype chain is searched. __ b(eq, &slow); masm->StubReturn(1);}class SetPropertyStub : public CodeStub { public: SetPropertyStub() { } private: Major MajorKey() { return SetProperty; } int MinorKey() { return 0; } void Generate(MacroAssembler* masm); const char* GetName() { return "GetPropertyStub"; }};void SetPropertyStub::Generate(MacroAssembler* masm) { // r0 : value // sp[0] : key // sp[1] : receiver Label slow, fast, array, extra, exit; // Get the key and the object from the stack. __ ldm(ia, sp, r1.bit() | r3.bit()); // r1 = key, r3 = receiver // Check that the key is a smi. __ tst(r1, Operand(kSmiTagMask)); __ b(ne, &slow); // Check that the object isn't a smi. __ tst(r3, Operand(kSmiTagMask)); __ b(eq, &slow); // Get the type of the object from its map. __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); // Check if the object is a JS array or not. __ cmp(r2, Operand(JS_ARRAY_TYPE)); __ b(eq, &array); // Check that the object is some kind of JS object. __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE)); __ b(lt, &slow);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -