Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1 | // Copyright 2012 the V8 project authors. All rights reserved. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 5 | #include "src/ast.h" |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 6 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 7 | #include <cmath> // For isfinite. |
| 8 | #include "src/builtins.h" |
| 9 | #include "src/code-stubs.h" |
| 10 | #include "src/contexts.h" |
| 11 | #include "src/conversions.h" |
| 12 | #include "src/hashmap.h" |
| 13 | #include "src/parser.h" |
| 14 | #include "src/property.h" |
| 15 | #include "src/property-details.h" |
| 16 | #include "src/scopes.h" |
| 17 | #include "src/string-stream.h" |
| 18 | #include "src/type-info.h" |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 19 | |
| 20 | namespace v8 { |
| 21 | namespace internal { |
| 22 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 23 | // ---------------------------------------------------------------------------- |
| 24 | // All the Accept member functions for each syntax tree node type. |
| 25 | |
Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 26 | #define DECL_ACCEPT(type) \ |
| 27 | void type::Accept(AstVisitor* v) { v->Visit##type(this); } |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 28 | AST_NODE_LIST(DECL_ACCEPT) |
| 29 | #undef DECL_ACCEPT |
| 30 | |
| 31 | |
| 32 | // ---------------------------------------------------------------------------- |
| 33 | // Implementation of other node functionality. |
| 34 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 35 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 36 | bool Expression::IsSmiLiteral() const { |
| 37 | return IsLiteral() && AsLiteral()->value()->IsSmi(); |
Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 38 | } |
| 39 | |
| 40 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 41 | bool Expression::IsStringLiteral() const { |
| 42 | return IsLiteral() && AsLiteral()->value()->IsString(); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 43 | } |
| 44 | |
| 45 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 46 | bool Expression::IsNullLiteral() const { |
| 47 | return IsLiteral() && AsLiteral()->value()->IsNull(); |
Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 48 | } |
| 49 | |
| 50 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 51 | bool Expression::IsUndefinedLiteral(Isolate* isolate) const { |
| 52 | const VariableProxy* var_proxy = AsVariableProxy(); |
| 53 | if (var_proxy == NULL) return false; |
| 54 | Variable* var = var_proxy->var(); |
| 55 | // The global identifier "undefined" is immutable. Everything |
| 56 | // else could be reassigned. |
| 57 | return var != NULL && var->location() == Variable::UNALLOCATED && |
| 58 | var_proxy->raw_name()->IsOneByteEqualTo("undefined"); |
| 59 | } |
| 60 | |
| 61 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 62 | VariableProxy::VariableProxy(Zone* zone, Variable* var, int position) |
| 63 | : Expression(zone, position), |
| 64 | bit_field_(IsThisField::encode(var->is_this()) | |
| 65 | IsAssignedField::encode(false) | |
| 66 | IsResolvedField::encode(false)), |
| 67 | variable_feedback_slot_(FeedbackVectorICSlot::Invalid()), |
| 68 | raw_name_(var->raw_name()), |
| 69 | interface_(var->interface()) { |
Kristian Monsen | 0d5e116 | 2010-09-30 15:31:59 +0100 | [diff] [blame] | 70 | BindTo(var); |
| 71 | } |
| 72 | |
| 73 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 74 | VariableProxy::VariableProxy(Zone* zone, const AstRawString* name, bool is_this, |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 75 | Interface* interface, int position) |
| 76 | : Expression(zone, position), |
| 77 | bit_field_(IsThisField::encode(is_this) | IsAssignedField::encode(false) | |
| 78 | IsResolvedField::encode(false)), |
| 79 | variable_feedback_slot_(FeedbackVectorICSlot::Invalid()), |
| 80 | raw_name_(name), |
| 81 | interface_(interface) {} |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 82 | |
| 83 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 84 | void VariableProxy::BindTo(Variable* var) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 85 | DCHECK(!FLAG_harmony_modules || interface_->IsUnified(var->interface())); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 86 | DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name()); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 87 | // Ideally CONST-ness should match. However, this is very hard to achieve |
| 88 | // because we don't know the exact semantics of conflicting (const and |
| 89 | // non-const) multiple variable declarations, const vars introduced via |
| 90 | // eval() etc. Const-ness and variable declarations are a complete mess |
| 91 | // in JS. Sigh... |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 92 | set_var(var); |
| 93 | set_is_resolved(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 94 | var->set_is_used(); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 95 | } |
| 96 | |
| 97 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 98 | Assignment::Assignment(Zone* zone, Token::Value op, Expression* target, |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 99 | Expression* value, int pos) |
| 100 | : Expression(zone, pos), |
| 101 | bit_field_(IsUninitializedField::encode(false) | |
| 102 | KeyTypeField::encode(ELEMENT) | |
| 103 | StoreModeField::encode(STANDARD_STORE) | |
| 104 | TokenField::encode(op)), |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 105 | target_(target), |
| 106 | value_(value), |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 107 | binary_operation_(NULL) {} |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 108 | |
| 109 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 110 | Token::Value Assignment::binary_op() const { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 111 | switch (op()) { |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 112 | case Token::ASSIGN_BIT_OR: return Token::BIT_OR; |
| 113 | case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR; |
| 114 | case Token::ASSIGN_BIT_AND: return Token::BIT_AND; |
| 115 | case Token::ASSIGN_SHL: return Token::SHL; |
| 116 | case Token::ASSIGN_SAR: return Token::SAR; |
| 117 | case Token::ASSIGN_SHR: return Token::SHR; |
| 118 | case Token::ASSIGN_ADD: return Token::ADD; |
| 119 | case Token::ASSIGN_SUB: return Token::SUB; |
| 120 | case Token::ASSIGN_MUL: return Token::MUL; |
| 121 | case Token::ASSIGN_DIV: return Token::DIV; |
| 122 | case Token::ASSIGN_MOD: return Token::MOD; |
| 123 | default: UNREACHABLE(); |
| 124 | } |
| 125 | return Token::ILLEGAL; |
| 126 | } |
| 127 | |
| 128 | |
| 129 | bool FunctionLiteral::AllowsLazyCompilation() { |
| 130 | return scope()->AllowsLazyCompilation(); |
| 131 | } |
| 132 | |
| 133 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 134 | bool FunctionLiteral::AllowsLazyCompilationWithoutContext() { |
| 135 | return scope()->AllowsLazyCompilationWithoutContext(); |
| 136 | } |
| 137 | |
| 138 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 139 | int FunctionLiteral::start_position() const { |
| 140 | return scope()->start_position(); |
| 141 | } |
| 142 | |
| 143 | |
| 144 | int FunctionLiteral::end_position() const { |
| 145 | return scope()->end_position(); |
| 146 | } |
| 147 | |
| 148 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 149 | StrictMode FunctionLiteral::strict_mode() const { |
| 150 | return scope()->strict_mode(); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 151 | } |
| 152 | |
| 153 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 154 | bool FunctionLiteral::uses_super_property() const { |
| 155 | DCHECK_NOT_NULL(scope()); |
| 156 | return scope()->uses_super_property() || scope()->inner_uses_super_property(); |
| 157 | } |
| 158 | |
| 159 | |
| 160 | bool FunctionLiteral::uses_super_constructor_call() const { |
| 161 | DCHECK_NOT_NULL(scope()); |
| 162 | return scope()->uses_super_constructor_call() || |
| 163 | scope()->inner_uses_super_constructor_call(); |
| 164 | } |
| 165 | |
| 166 | |
| 167 | // Helper to find an existing shared function info in the baseline code for the |
| 168 | // given function literal. Used to canonicalize SharedFunctionInfo objects. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 169 | void FunctionLiteral::InitializeSharedInfo( |
| 170 | Handle<Code> unoptimized_code) { |
| 171 | for (RelocIterator it(*unoptimized_code); !it.done(); it.next()) { |
| 172 | RelocInfo* rinfo = it.rinfo(); |
| 173 | if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue; |
| 174 | Object* obj = rinfo->target_object(); |
| 175 | if (obj->IsSharedFunctionInfo()) { |
| 176 | SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); |
| 177 | if (shared->start_position() == start_position()) { |
| 178 | shared_info_ = Handle<SharedFunctionInfo>(shared); |
| 179 | break; |
| 180 | } |
| 181 | } |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | |
| 186 | ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, |
| 187 | AstValueFactory* ast_value_factory, |
| 188 | Literal* key, Expression* value, |
| 189 | bool is_static) { |
Teng-Hui Zhu | 3e5fa29 | 2010-11-09 16:16:48 -0800 | [diff] [blame] | 190 | emit_store_ = true; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 191 | key_ = key; |
| 192 | value_ = value; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 193 | is_static_ = is_static; |
| 194 | if (key->raw_value()->EqualsString(ast_value_factory->proto_string())) { |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 195 | kind_ = PROTOTYPE; |
| 196 | } else if (value_->AsMaterializedLiteral() != NULL) { |
| 197 | kind_ = MATERIALIZED_LITERAL; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 198 | } else if (value_->IsLiteral()) { |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 199 | kind_ = CONSTANT; |
| 200 | } else { |
| 201 | kind_ = COMPUTED; |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 206 | ObjectLiteralProperty::ObjectLiteralProperty(Zone* zone, bool is_getter, |
| 207 | FunctionLiteral* value, |
| 208 | bool is_static) { |
Teng-Hui Zhu | 3e5fa29 | 2010-11-09 16:16:48 -0800 | [diff] [blame] | 209 | emit_store_ = true; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 210 | value_ = value; |
| 211 | kind_ = is_getter ? GETTER : SETTER; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 212 | is_static_ = is_static; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 213 | } |
| 214 | |
| 215 | |
Steve Block | d0582a6 | 2009-12-15 09:54:21 +0000 | [diff] [blame] | 216 | bool ObjectLiteral::Property::IsCompileTimeValue() { |
| 217 | return kind_ == CONSTANT || |
| 218 | (kind_ == MATERIALIZED_LITERAL && |
| 219 | CompileTimeValue::IsCompileTimeValue(value_)); |
| 220 | } |
| 221 | |
| 222 | |
Teng-Hui Zhu | 3e5fa29 | 2010-11-09 16:16:48 -0800 | [diff] [blame] | 223 | void ObjectLiteral::Property::set_emit_store(bool emit_store) { |
| 224 | emit_store_ = emit_store; |
| 225 | } |
| 226 | |
| 227 | |
| 228 | bool ObjectLiteral::Property::emit_store() { |
| 229 | return emit_store_; |
| 230 | } |
| 231 | |
| 232 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 233 | void ObjectLiteral::CalculateEmitStore(Zone* zone) { |
| 234 | ZoneAllocationPolicy allocator(zone); |
Teng-Hui Zhu | 3e5fa29 | 2010-11-09 16:16:48 -0800 | [diff] [blame] | 235 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 236 | ZoneHashMap table(Literal::Match, ZoneHashMap::kDefaultHashMapCapacity, |
| 237 | allocator); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 238 | for (int i = properties()->length() - 1; i >= 0; i--) { |
| 239 | ObjectLiteral::Property* property = properties()->at(i); |
Teng-Hui Zhu | 3e5fa29 | 2010-11-09 16:16:48 -0800 | [diff] [blame] | 240 | Literal* literal = property->key(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 241 | if (literal->value()->IsNull()) continue; |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 242 | uint32_t hash = literal->Hash(); |
Teng-Hui Zhu | 3e5fa29 | 2010-11-09 16:16:48 -0800 | [diff] [blame] | 243 | // If the key of a computed property is in the table, do not emit |
| 244 | // a store for the property later. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 245 | if ((property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL || |
| 246 | property->kind() == ObjectLiteral::Property::COMPUTED) && |
| 247 | table.Lookup(literal, hash, false, allocator) != NULL) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 248 | property->set_emit_store(false); |
| 249 | } else { |
| 250 | // Add key to the table. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 251 | table.Lookup(literal, hash, true, allocator); |
Teng-Hui Zhu | 3e5fa29 | 2010-11-09 16:16:48 -0800 | [diff] [blame] | 252 | } |
Teng-Hui Zhu | 3e5fa29 | 2010-11-09 16:16:48 -0800 | [diff] [blame] | 253 | } |
| 254 | } |
| 255 | |
| 256 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 257 | bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) { |
| 258 | return property != NULL && |
| 259 | property->kind() != ObjectLiteral::Property::PROTOTYPE; |
| 260 | } |
| 261 | |
| 262 | |
| 263 | void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { |
| 264 | if (!constant_properties_.is_null()) return; |
| 265 | |
| 266 | // Allocate a fixed array to hold all the constant properties. |
| 267 | Handle<FixedArray> constant_properties = isolate->factory()->NewFixedArray( |
| 268 | boilerplate_properties_ * 2, TENURED); |
| 269 | |
| 270 | int position = 0; |
| 271 | // Accumulate the value in local variables and store it at the end. |
| 272 | bool is_simple = true; |
| 273 | int depth_acc = 1; |
| 274 | uint32_t max_element_index = 0; |
| 275 | uint32_t elements = 0; |
| 276 | for (int i = 0; i < properties()->length(); i++) { |
| 277 | ObjectLiteral::Property* property = properties()->at(i); |
| 278 | if (!IsBoilerplateProperty(property)) { |
| 279 | is_simple = false; |
| 280 | continue; |
| 281 | } |
| 282 | MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); |
| 283 | if (m_literal != NULL) { |
| 284 | m_literal->BuildConstants(isolate); |
| 285 | if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1; |
| 286 | } |
| 287 | |
| 288 | // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined |
| 289 | // value for COMPUTED properties, the real value is filled in at |
| 290 | // runtime. The enumeration order is maintained. |
| 291 | Handle<Object> key = property->key()->value(); |
| 292 | Handle<Object> value = GetBoilerplateValue(property->value(), isolate); |
| 293 | |
| 294 | // Ensure objects that may, at any point in time, contain fields with double |
| 295 | // representation are always treated as nested objects. This is true for |
| 296 | // computed fields (value is undefined), and smi and double literals |
| 297 | // (value->IsNumber()). |
| 298 | // TODO(verwaest): Remove once we can store them inline. |
| 299 | if (FLAG_track_double_fields && |
| 300 | (value->IsNumber() || value->IsUninitialized())) { |
| 301 | may_store_doubles_ = true; |
| 302 | } |
| 303 | |
| 304 | is_simple = is_simple && !value->IsUninitialized(); |
| 305 | |
| 306 | // Keep track of the number of elements in the object literal and |
| 307 | // the largest element index. If the largest element index is |
| 308 | // much larger than the number of elements, creating an object |
| 309 | // literal with fast elements will be a waste of space. |
| 310 | uint32_t element_index = 0; |
| 311 | if (key->IsString() |
| 312 | && Handle<String>::cast(key)->AsArrayIndex(&element_index) |
| 313 | && element_index > max_element_index) { |
| 314 | max_element_index = element_index; |
| 315 | elements++; |
| 316 | } else if (key->IsSmi()) { |
| 317 | int key_value = Smi::cast(*key)->value(); |
| 318 | if (key_value > 0 |
| 319 | && static_cast<uint32_t>(key_value) > max_element_index) { |
| 320 | max_element_index = key_value; |
| 321 | } |
| 322 | elements++; |
| 323 | } |
| 324 | |
| 325 | // Add name, value pair to the fixed array. |
| 326 | constant_properties->set(position++, *key); |
| 327 | constant_properties->set(position++, *value); |
| 328 | } |
| 329 | |
| 330 | constant_properties_ = constant_properties; |
| 331 | fast_elements_ = |
| 332 | (max_element_index <= 32) || ((2 * elements) >= max_element_index); |
| 333 | set_is_simple(is_simple); |
| 334 | set_depth(depth_acc); |
| 335 | } |
| 336 | |
| 337 | |
| 338 | void ArrayLiteral::BuildConstantElements(Isolate* isolate) { |
| 339 | if (!constant_elements_.is_null()) return; |
| 340 | |
| 341 | // Allocate a fixed array to hold all the object literals. |
| 342 | Handle<JSArray> array = |
| 343 | isolate->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS); |
| 344 | JSArray::Expand(array, values()->length()); |
| 345 | |
| 346 | // Fill in the literals. |
| 347 | bool is_simple = true; |
| 348 | int depth_acc = 1; |
| 349 | bool is_holey = false; |
| 350 | for (int i = 0, n = values()->length(); i < n; i++) { |
| 351 | Expression* element = values()->at(i); |
| 352 | MaterializedLiteral* m_literal = element->AsMaterializedLiteral(); |
| 353 | if (m_literal != NULL) { |
| 354 | m_literal->BuildConstants(isolate); |
| 355 | if (m_literal->depth() + 1 > depth_acc) { |
| 356 | depth_acc = m_literal->depth() + 1; |
| 357 | } |
| 358 | } |
| 359 | Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate); |
| 360 | if (boilerplate_value->IsTheHole()) { |
| 361 | is_holey = true; |
| 362 | } else if (boilerplate_value->IsUninitialized()) { |
| 363 | is_simple = false; |
| 364 | JSObject::SetOwnElement( |
| 365 | array, i, handle(Smi::FromInt(0), isolate), SLOPPY).Assert(); |
| 366 | } else { |
| 367 | JSObject::SetOwnElement(array, i, boilerplate_value, SLOPPY).Assert(); |
| 368 | } |
| 369 | } |
| 370 | |
| 371 | Handle<FixedArrayBase> element_values(array->elements()); |
| 372 | |
| 373 | // Simple and shallow arrays can be lazily copied, we transform the |
| 374 | // elements array to a copy-on-write array. |
| 375 | if (is_simple && depth_acc == 1 && values()->length() > 0 && |
| 376 | array->HasFastSmiOrObjectElements()) { |
| 377 | element_values->set_map(isolate->heap()->fixed_cow_array_map()); |
| 378 | } |
| 379 | |
| 380 | // Remember both the literal's constant values as well as the ElementsKind |
| 381 | // in a 2-element FixedArray. |
| 382 | Handle<FixedArray> literals = isolate->factory()->NewFixedArray(2, TENURED); |
| 383 | |
| 384 | ElementsKind kind = array->GetElementsKind(); |
| 385 | kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind); |
| 386 | |
| 387 | literals->set(0, Smi::FromInt(kind)); |
| 388 | literals->set(1, *element_values); |
| 389 | |
| 390 | constant_elements_ = literals; |
| 391 | set_is_simple(is_simple); |
| 392 | set_depth(depth_acc); |
| 393 | } |
| 394 | |
| 395 | |
| 396 | Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression, |
| 397 | Isolate* isolate) { |
| 398 | if (expression->IsLiteral()) { |
| 399 | return expression->AsLiteral()->value(); |
| 400 | } |
| 401 | if (CompileTimeValue::IsCompileTimeValue(expression)) { |
| 402 | return CompileTimeValue::GetValue(isolate, expression); |
| 403 | } |
| 404 | return isolate->factory()->uninitialized_value(); |
| 405 | } |
| 406 | |
| 407 | |
| 408 | void MaterializedLiteral::BuildConstants(Isolate* isolate) { |
| 409 | if (IsArrayLiteral()) { |
| 410 | return AsArrayLiteral()->BuildConstantElements(isolate); |
| 411 | } |
| 412 | if (IsObjectLiteral()) { |
| 413 | return AsObjectLiteral()->BuildConstantProperties(isolate); |
| 414 | } |
| 415 | DCHECK(IsRegExpLiteral()); |
| 416 | DCHECK(depth() >= 1); // Depth should be initialized. |
| 417 | } |
| 418 | |
| 419 | |
| 420 | void TargetCollector::AddTarget(Label* target, Zone* zone) { |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 421 | // Add the label to the collector, but discard duplicates. |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 422 | int length = targets_.length(); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 423 | for (int i = 0; i < length; i++) { |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 424 | if (targets_[i] == target) return; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 425 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 426 | targets_.Add(target, zone); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 427 | } |
| 428 | |
| 429 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 430 | void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { |
| 431 | // TODO(olivf) If this Operation is used in a test context, then the |
| 432 | // expression has a ToBoolean stub and we want to collect the type |
| 433 | // information. However the GraphBuilder expects it to be on the instruction |
| 434 | // corresponding to the TestContext, therefore we have to store it here and |
| 435 | // not on the operand. |
| 436 | set_to_boolean_types(oracle->ToBooleanTypes(expression()->test_id())); |
Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 437 | } |
| 438 | |
| 439 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 440 | void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { |
| 441 | // TODO(olivf) If this Operation is used in a test context, then the right |
| 442 | // hand side has a ToBoolean stub and we want to collect the type information. |
| 443 | // However the GraphBuilder expects it to be on the instruction corresponding |
| 444 | // to the TestContext, therefore we have to store it here and not on the |
| 445 | // right hand operand. |
| 446 | set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id())); |
| 447 | } |
| 448 | |
| 449 | |
| 450 | bool BinaryOperation::ResultOverwriteAllowed() const { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 451 | switch (op()) { |
Kristian Monsen | 80d68ea | 2010-09-08 11:05:35 +0100 | [diff] [blame] | 452 | case Token::COMMA: |
| 453 | case Token::OR: |
| 454 | case Token::AND: |
| 455 | return false; |
| 456 | case Token::BIT_OR: |
| 457 | case Token::BIT_XOR: |
| 458 | case Token::BIT_AND: |
| 459 | case Token::SHL: |
| 460 | case Token::SAR: |
| 461 | case Token::SHR: |
| 462 | case Token::ADD: |
| 463 | case Token::SUB: |
| 464 | case Token::MUL: |
| 465 | case Token::DIV: |
| 466 | case Token::MOD: |
| 467 | return true; |
| 468 | default: |
| 469 | UNREACHABLE(); |
| 470 | } |
| 471 | return false; |
| 472 | } |
| 473 | |
| 474 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 475 | static bool IsTypeof(Expression* expr) { |
| 476 | UnaryOperation* maybe_unary = expr->AsUnaryOperation(); |
| 477 | return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF; |
| 478 | } |
| 479 | |
| 480 | |
| 481 | // Check for the pattern: typeof <expression> equals <string literal>. |
| 482 | static bool MatchLiteralCompareTypeof(Expression* left, |
| 483 | Token::Value op, |
| 484 | Expression* right, |
| 485 | Expression** expr, |
| 486 | Handle<String>* check) { |
| 487 | if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) { |
| 488 | *expr = left->AsUnaryOperation()->expression(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 489 | *check = Handle<String>::cast(right->AsLiteral()->value()); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 490 | return true; |
| 491 | } |
| 492 | return false; |
| 493 | } |
| 494 | |
| 495 | |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 496 | bool CompareOperation::IsLiteralCompareTypeof(Expression** expr, |
| 497 | Handle<String>* check) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 498 | return MatchLiteralCompareTypeof(left_, op_, right_, expr, check) || |
| 499 | MatchLiteralCompareTypeof(right_, op_, left_, expr, check); |
| 500 | } |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 501 | |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 502 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 503 | static bool IsVoidOfLiteral(Expression* expr) { |
| 504 | UnaryOperation* maybe_unary = expr->AsUnaryOperation(); |
| 505 | return maybe_unary != NULL && |
| 506 | maybe_unary->op() == Token::VOID && |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 507 | maybe_unary->expression()->IsLiteral(); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 508 | } |
| 509 | |
| 510 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 511 | // Check for the pattern: void <literal> equals <expression> or |
| 512 | // undefined equals <expression> |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 513 | static bool MatchLiteralCompareUndefined(Expression* left, |
| 514 | Token::Value op, |
| 515 | Expression* right, |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 516 | Expression** expr, |
| 517 | Isolate* isolate) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 518 | if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) { |
| 519 | *expr = right; |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 520 | return true; |
| 521 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 522 | if (left->IsUndefinedLiteral(isolate) && Token::IsEqualityOp(op)) { |
| 523 | *expr = right; |
| 524 | return true; |
| 525 | } |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 526 | return false; |
| 527 | } |
| 528 | |
| 529 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 530 | bool CompareOperation::IsLiteralCompareUndefined( |
| 531 | Expression** expr, Isolate* isolate) { |
| 532 | return MatchLiteralCompareUndefined(left_, op_, right_, expr, isolate) || |
| 533 | MatchLiteralCompareUndefined(right_, op_, left_, expr, isolate); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 534 | } |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 535 | |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 536 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 537 | // Check for the pattern: null equals <expression> |
| 538 | static bool MatchLiteralCompareNull(Expression* left, |
| 539 | Token::Value op, |
| 540 | Expression* right, |
| 541 | Expression** expr) { |
| 542 | if (left->IsNullLiteral() && Token::IsEqualityOp(op)) { |
| 543 | *expr = right; |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 544 | return true; |
| 545 | } |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 546 | return false; |
| 547 | } |
| 548 | |
| 549 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 550 | bool CompareOperation::IsLiteralCompareNull(Expression** expr) { |
| 551 | return MatchLiteralCompareNull(left_, op_, right_, expr) || |
| 552 | MatchLiteralCompareNull(right_, op_, left_, expr); |
| 553 | } |
| 554 | |
| 555 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 556 | // ---------------------------------------------------------------------------- |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 557 | // Inlining support |
| 558 | |
Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 559 | bool Declaration::IsInlineable() const { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 560 | return proxy()->var()->IsStackAllocated(); |
Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 561 | } |
| 562 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 563 | bool FunctionDeclaration::IsInlineable() const { |
Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 564 | return false; |
| 565 | } |
| 566 | |
| 567 | |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 568 | // ---------------------------------------------------------------------------- |
| 569 | // Recording of type feedback |
| 570 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 571 | // TODO(rossberg): all RecordTypeFeedback functions should disappear |
| 572 | // once we use the common type field in the AST consistently. |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 573 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 574 | void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 575 | set_to_boolean_types(oracle->ToBooleanTypes(test_id())); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 576 | } |
| 577 | |
| 578 | |
| 579 | bool Call::IsUsingCallFeedbackSlot(Isolate* isolate) const { |
| 580 | CallType call_type = GetCallType(isolate); |
| 581 | return (call_type != POSSIBLY_EVAL_CALL); |
| 582 | } |
| 583 | |
| 584 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 585 | FeedbackVectorRequirements Call::ComputeFeedbackRequirements(Isolate* isolate) { |
| 586 | int ic_slots = IsUsingCallFeedbackSlot(isolate) ? 1 : 0; |
| 587 | return FeedbackVectorRequirements(0, ic_slots); |
| 588 | } |
| 589 | |
| 590 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 591 | Call::CallType Call::GetCallType(Isolate* isolate) const { |
| 592 | VariableProxy* proxy = expression()->AsVariableProxy(); |
| 593 | if (proxy != NULL) { |
| 594 | if (proxy->var()->is_possibly_eval(isolate)) { |
| 595 | return POSSIBLY_EVAL_CALL; |
| 596 | } else if (proxy->var()->IsUnallocated()) { |
| 597 | return GLOBAL_CALL; |
| 598 | } else if (proxy->var()->IsLookupSlot()) { |
| 599 | return LOOKUP_SLOT_CALL; |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 600 | } |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 601 | } |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 602 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 603 | if (expression()->AsSuperReference() != NULL) return SUPER_CALL; |
| 604 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 605 | Property* property = expression()->AsProperty(); |
| 606 | return property != NULL ? PROPERTY_CALL : OTHER_CALL; |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 607 | } |
| 608 | |
| 609 | |
| 610 | bool Call::ComputeGlobalTarget(Handle<GlobalObject> global, |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 611 | LookupIterator* it) { |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 612 | target_ = Handle<JSFunction>::null(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 613 | cell_ = Handle<Cell>::null(); |
| 614 | DCHECK(it->IsFound() && it->GetHolder<JSObject>().is_identical_to(global)); |
| 615 | cell_ = it->GetPropertyCell(); |
Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 616 | if (cell_->value()->IsJSFunction()) { |
| 617 | Handle<JSFunction> candidate(JSFunction::cast(cell_->value())); |
| 618 | // If the function is in new space we assume it's more likely to |
| 619 | // change and thus prefer the general IC code. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 620 | if (!it->isolate()->heap()->InNewSpace(*candidate)) { |
Ben Murdoch | 8b112d2 | 2011-06-08 16:22:53 +0100 | [diff] [blame] | 621 | target_ = candidate; |
| 622 | return true; |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 623 | } |
| 624 | } |
| 625 | return false; |
| 626 | } |
| 627 | |
| 628 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 629 | void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 630 | FeedbackVectorSlot allocation_site_feedback_slot = |
| 631 | FLAG_pretenuring_call_new ? AllocationSiteFeedbackSlot() |
| 632 | : CallNewFeedbackSlot(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 633 | allocation_site_ = |
| 634 | oracle->GetCallNewAllocationSite(allocation_site_feedback_slot); |
| 635 | is_monomorphic_ = oracle->CallNewIsMonomorphic(CallNewFeedbackSlot()); |
Ben Murdoch | 5d4cdbf | 2012-04-11 10:23:59 +0100 | [diff] [blame] | 636 | if (is_monomorphic_) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 637 | target_ = oracle->GetCallNewTarget(CallNewFeedbackSlot()); |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 638 | } |
| 639 | } |
| 640 | |
| 641 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 642 | void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 643 | TypeFeedbackId id = key()->LiteralFeedbackId(); |
| 644 | SmallMapList maps; |
| 645 | oracle->CollectReceiverTypes(id, &maps); |
| 646 | receiver_type_ = maps.length() == 1 ? maps.at(0) |
| 647 | : Handle<Map>::null(); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 648 | } |
| 649 | |
| 650 | |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 651 | // ---------------------------------------------------------------------------- |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 652 | // Implementation of AstVisitor |
| 653 | |
Steve Block | 3ce2e20 | 2009-11-05 08:53:23 +0000 | [diff] [blame] | 654 | void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) { |
| 655 | for (int i = 0; i < declarations->length(); i++) { |
| 656 | Visit(declarations->at(i)); |
| 657 | } |
| 658 | } |
| 659 | |
| 660 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 661 | void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) { |
| 662 | for (int i = 0; i < statements->length(); i++) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 663 | Statement* stmt = statements->at(i); |
| 664 | Visit(stmt); |
| 665 | if (stmt->IsJump()) break; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 666 | } |
| 667 | } |
| 668 | |
| 669 | |
| 670 | void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) { |
| 671 | for (int i = 0; i < expressions->length(); i++) { |
| 672 | // The variable statement visiting code may pass NULL expressions |
| 673 | // to this code. Maybe this should be handled by introducing an |
| 674 | // undefined expression or literal? Revisit this code if this |
| 675 | // changes |
| 676 | Expression* expression = expressions->at(i); |
| 677 | if (expression != NULL) Visit(expression); |
| 678 | } |
| 679 | } |
| 680 | |
| 681 | |
| 682 | // ---------------------------------------------------------------------------- |
| 683 | // Regular expressions |
| 684 | |
| 685 | #define MAKE_ACCEPT(Name) \ |
| 686 | void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) { \ |
| 687 | return visitor->Visit##Name(this, data); \ |
| 688 | } |
| 689 | FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ACCEPT) |
| 690 | #undef MAKE_ACCEPT |
| 691 | |
| 692 | #define MAKE_TYPE_CASE(Name) \ |
| 693 | RegExp##Name* RegExpTree::As##Name() { \ |
| 694 | return NULL; \ |
| 695 | } \ |
| 696 | bool RegExpTree::Is##Name() { return false; } |
| 697 | FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE) |
| 698 | #undef MAKE_TYPE_CASE |
| 699 | |
| 700 | #define MAKE_TYPE_CASE(Name) \ |
| 701 | RegExp##Name* RegExp##Name::As##Name() { \ |
| 702 | return this; \ |
| 703 | } \ |
| 704 | bool RegExp##Name::Is##Name() { return true; } |
| 705 | FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE) |
| 706 | #undef MAKE_TYPE_CASE |
| 707 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 708 | |
| 709 | static Interval ListCaptureRegisters(ZoneList<RegExpTree*>* children) { |
| 710 | Interval result = Interval::Empty(); |
| 711 | for (int i = 0; i < children->length(); i++) |
| 712 | result = result.Union(children->at(i)->CaptureRegisters()); |
| 713 | return result; |
| 714 | } |
| 715 | |
| 716 | |
| 717 | Interval RegExpAlternative::CaptureRegisters() { |
| 718 | return ListCaptureRegisters(nodes()); |
| 719 | } |
| 720 | |
| 721 | |
| 722 | Interval RegExpDisjunction::CaptureRegisters() { |
| 723 | return ListCaptureRegisters(alternatives()); |
| 724 | } |
| 725 | |
| 726 | |
| 727 | Interval RegExpLookahead::CaptureRegisters() { |
| 728 | return body()->CaptureRegisters(); |
| 729 | } |
| 730 | |
| 731 | |
| 732 | Interval RegExpCapture::CaptureRegisters() { |
| 733 | Interval self(StartRegister(index()), EndRegister(index())); |
| 734 | return self.Union(body()->CaptureRegisters()); |
| 735 | } |
| 736 | |
| 737 | |
| 738 | Interval RegExpQuantifier::CaptureRegisters() { |
| 739 | return body()->CaptureRegisters(); |
| 740 | } |
| 741 | |
| 742 | |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 743 | bool RegExpAssertion::IsAnchoredAtStart() { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 744 | return assertion_type() == RegExpAssertion::START_OF_INPUT; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 745 | } |
| 746 | |
| 747 | |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 748 | bool RegExpAssertion::IsAnchoredAtEnd() { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 749 | return assertion_type() == RegExpAssertion::END_OF_INPUT; |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 750 | } |
| 751 | |
| 752 | |
| 753 | bool RegExpAlternative::IsAnchoredAtStart() { |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 754 | ZoneList<RegExpTree*>* nodes = this->nodes(); |
| 755 | for (int i = 0; i < nodes->length(); i++) { |
| 756 | RegExpTree* node = nodes->at(i); |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 757 | if (node->IsAnchoredAtStart()) { return true; } |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 758 | if (node->max_match() > 0) { return false; } |
| 759 | } |
| 760 | return false; |
| 761 | } |
| 762 | |
| 763 | |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 764 | bool RegExpAlternative::IsAnchoredAtEnd() { |
| 765 | ZoneList<RegExpTree*>* nodes = this->nodes(); |
| 766 | for (int i = nodes->length() - 1; i >= 0; i--) { |
| 767 | RegExpTree* node = nodes->at(i); |
| 768 | if (node->IsAnchoredAtEnd()) { return true; } |
| 769 | if (node->max_match() > 0) { return false; } |
| 770 | } |
| 771 | return false; |
| 772 | } |
| 773 | |
| 774 | |
| 775 | bool RegExpDisjunction::IsAnchoredAtStart() { |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 776 | ZoneList<RegExpTree*>* alternatives = this->alternatives(); |
| 777 | for (int i = 0; i < alternatives->length(); i++) { |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 778 | if (!alternatives->at(i)->IsAnchoredAtStart()) |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 779 | return false; |
| 780 | } |
| 781 | return true; |
| 782 | } |
| 783 | |
| 784 | |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 785 | bool RegExpDisjunction::IsAnchoredAtEnd() { |
| 786 | ZoneList<RegExpTree*>* alternatives = this->alternatives(); |
| 787 | for (int i = 0; i < alternatives->length(); i++) { |
| 788 | if (!alternatives->at(i)->IsAnchoredAtEnd()) |
| 789 | return false; |
| 790 | } |
| 791 | return true; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 792 | } |
| 793 | |
| 794 | |
Ben Murdoch | f87a203 | 2010-10-22 12:50:53 +0100 | [diff] [blame] | 795 | bool RegExpLookahead::IsAnchoredAtStart() { |
| 796 | return is_positive() && body()->IsAnchoredAtStart(); |
| 797 | } |
| 798 | |
| 799 | |
| 800 | bool RegExpCapture::IsAnchoredAtStart() { |
| 801 | return body()->IsAnchoredAtStart(); |
| 802 | } |
| 803 | |
| 804 | |
| 805 | bool RegExpCapture::IsAnchoredAtEnd() { |
| 806 | return body()->IsAnchoredAtEnd(); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 807 | } |
| 808 | |
| 809 | |
| 810 | // Convert regular expression trees to a simple sexp representation. |
| 811 | // This representation should be different from the input grammar |
| 812 | // in as many cases as possible, to make it more difficult for incorrect |
| 813 | // parses to look as correct ones which is likely if the input and |
| 814 | // output formats are alike. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 815 | class RegExpUnparser FINAL : public RegExpVisitor { |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 816 | public: |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 817 | RegExpUnparser(std::ostream& os, Zone* zone) : os_(os), zone_(zone) {} |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 818 | void VisitCharacterRange(CharacterRange that); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 819 | #define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, \ |
| 820 | void* data) OVERRIDE; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 821 | FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE) |
| 822 | #undef MAKE_CASE |
| 823 | private: |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 824 | std::ostream& os_; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 825 | Zone* zone_; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 826 | }; |
| 827 | |
| 828 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 829 | void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 830 | os_ << "(|"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 831 | for (int i = 0; i < that->alternatives()->length(); i++) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 832 | os_ << " "; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 833 | that->alternatives()->at(i)->Accept(this, data); |
| 834 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 835 | os_ << ")"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 836 | return NULL; |
| 837 | } |
| 838 | |
| 839 | |
| 840 | void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 841 | os_ << "(:"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 842 | for (int i = 0; i < that->nodes()->length(); i++) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 843 | os_ << " "; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 844 | that->nodes()->at(i)->Accept(this, data); |
| 845 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 846 | os_ << ")"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 847 | return NULL; |
| 848 | } |
| 849 | |
| 850 | |
| 851 | void RegExpUnparser::VisitCharacterRange(CharacterRange that) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 852 | os_ << AsUC16(that.from()); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 853 | if (!that.IsSingleton()) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 854 | os_ << "-" << AsUC16(that.to()); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 855 | } |
| 856 | } |
| 857 | |
| 858 | |
| 859 | |
| 860 | void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that, |
| 861 | void* data) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 862 | if (that->is_negated()) os_ << "^"; |
| 863 | os_ << "["; |
| 864 | for (int i = 0; i < that->ranges(zone_)->length(); i++) { |
| 865 | if (i > 0) os_ << " "; |
| 866 | VisitCharacterRange(that->ranges(zone_)->at(i)); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 867 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 868 | os_ << "]"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 869 | return NULL; |
| 870 | } |
| 871 | |
| 872 | |
| 873 | void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 874 | switch (that->assertion_type()) { |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 875 | case RegExpAssertion::START_OF_INPUT: |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 876 | os_ << "@^i"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 877 | break; |
| 878 | case RegExpAssertion::END_OF_INPUT: |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 879 | os_ << "@$i"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 880 | break; |
| 881 | case RegExpAssertion::START_OF_LINE: |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 882 | os_ << "@^l"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 883 | break; |
| 884 | case RegExpAssertion::END_OF_LINE: |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 885 | os_ << "@$l"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 886 | break; |
| 887 | case RegExpAssertion::BOUNDARY: |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 888 | os_ << "@b"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 889 | break; |
| 890 | case RegExpAssertion::NON_BOUNDARY: |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 891 | os_ << "@B"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 892 | break; |
| 893 | } |
| 894 | return NULL; |
| 895 | } |
| 896 | |
| 897 | |
| 898 | void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 899 | os_ << "'"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 900 | Vector<const uc16> chardata = that->data(); |
| 901 | for (int i = 0; i < chardata.length(); i++) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 902 | os_ << AsUC16(chardata[i]); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 903 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 904 | os_ << "'"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 905 | return NULL; |
| 906 | } |
| 907 | |
| 908 | |
| 909 | void* RegExpUnparser::VisitText(RegExpText* that, void* data) { |
| 910 | if (that->elements()->length() == 1) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 911 | that->elements()->at(0).tree()->Accept(this, data); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 912 | } else { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 913 | os_ << "(!"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 914 | for (int i = 0; i < that->elements()->length(); i++) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 915 | os_ << " "; |
| 916 | that->elements()->at(i).tree()->Accept(this, data); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 917 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 918 | os_ << ")"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 919 | } |
| 920 | return NULL; |
| 921 | } |
| 922 | |
| 923 | |
| 924 | void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 925 | os_ << "(# " << that->min() << " "; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 926 | if (that->max() == RegExpTree::kInfinity) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 927 | os_ << "- "; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 928 | } else { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 929 | os_ << that->max() << " "; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 930 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 931 | os_ << (that->is_greedy() ? "g " : that->is_possessive() ? "p " : "n "); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 932 | that->body()->Accept(this, data); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 933 | os_ << ")"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 934 | return NULL; |
| 935 | } |
| 936 | |
| 937 | |
| 938 | void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 939 | os_ << "(^ "; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 940 | that->body()->Accept(this, data); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 941 | os_ << ")"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 942 | return NULL; |
| 943 | } |
| 944 | |
| 945 | |
| 946 | void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 947 | os_ << "(-> " << (that->is_positive() ? "+ " : "- "); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 948 | that->body()->Accept(this, data); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 949 | os_ << ")"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 950 | return NULL; |
| 951 | } |
| 952 | |
| 953 | |
| 954 | void* RegExpUnparser::VisitBackReference(RegExpBackReference* that, |
| 955 | void* data) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 956 | os_ << "(<- " << that->index() << ")"; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 957 | return NULL; |
| 958 | } |
| 959 | |
| 960 | |
| 961 | void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 962 | os_ << '%'; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 963 | return NULL; |
| 964 | } |
| 965 | |
| 966 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 967 | std::ostream& RegExpTree::Print(std::ostream& os, Zone* zone) { // NOLINT |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 968 | RegExpUnparser unparser(os, zone); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 969 | Accept(&unparser, NULL); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 970 | return os; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 971 | } |
| 972 | |
| 973 | |
| 974 | RegExpDisjunction::RegExpDisjunction(ZoneList<RegExpTree*>* alternatives) |
| 975 | : alternatives_(alternatives) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 976 | DCHECK(alternatives->length() > 1); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 977 | RegExpTree* first_alternative = alternatives->at(0); |
| 978 | min_match_ = first_alternative->min_match(); |
| 979 | max_match_ = first_alternative->max_match(); |
| 980 | for (int i = 1; i < alternatives->length(); i++) { |
| 981 | RegExpTree* alternative = alternatives->at(i); |
| 982 | min_match_ = Min(min_match_, alternative->min_match()); |
| 983 | max_match_ = Max(max_match_, alternative->max_match()); |
| 984 | } |
| 985 | } |
| 986 | |
| 987 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 988 | static int IncreaseBy(int previous, int increase) { |
| 989 | if (RegExpTree::kInfinity - previous < increase) { |
| 990 | return RegExpTree::kInfinity; |
| 991 | } else { |
| 992 | return previous + increase; |
| 993 | } |
| 994 | } |
| 995 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 996 | RegExpAlternative::RegExpAlternative(ZoneList<RegExpTree*>* nodes) |
| 997 | : nodes_(nodes) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 998 | DCHECK(nodes->length() > 1); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 999 | min_match_ = 0; |
| 1000 | max_match_ = 0; |
| 1001 | for (int i = 0; i < nodes->length(); i++) { |
| 1002 | RegExpTree* node = nodes->at(i); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1003 | int node_min_match = node->min_match(); |
| 1004 | min_match_ = IncreaseBy(min_match_, node_min_match); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1005 | int node_max_match = node->max_match(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1006 | max_match_ = IncreaseBy(max_match_, node_max_match); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1007 | } |
| 1008 | } |
| 1009 | |
Steve Block | 6ded16b | 2010-05-10 14:33:55 +0100 | [diff] [blame] | 1010 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1011 | CaseClause::CaseClause(Zone* zone, Expression* label, |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 1012 | ZoneList<Statement*>* statements, int pos) |
| 1013 | : Expression(zone, pos), |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1014 | label_(label), |
Ben Murdoch | b0fe162 | 2011-05-05 13:52:32 +0100 | [diff] [blame] | 1015 | statements_(statements), |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 1016 | compare_type_(Type::None(zone)) {} |
Kristian Monsen | 25f6136 | 2010-05-21 11:50:48 +0100 | [diff] [blame] | 1017 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1018 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 1019 | uint32_t Literal::Hash() { |
| 1020 | return raw_value()->IsString() |
| 1021 | ? raw_value()->AsString()->hash() |
| 1022 | : ComputeLongHash(double_to_uint64(raw_value()->AsNumber())); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1023 | } |
| 1024 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1025 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 1026 | // static |
| 1027 | bool Literal::Match(void* literal1, void* literal2) { |
| 1028 | const AstValue* x = static_cast<Literal*>(literal1)->raw_value(); |
| 1029 | const AstValue* y = static_cast<Literal*>(literal2)->raw_value(); |
| 1030 | return (x->IsString() && y->IsString() && *x->AsString() == *y->AsString()) || |
| 1031 | (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber()); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1032 | } |
| 1033 | |
| 1034 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1035 | } } // namespace v8::internal |