blob: f6bd294bfd1c7939f7c285dba8324ed8a1851daf [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000045#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000046#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000047#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#include "platform.h"
49#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000052#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000053#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000054#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000055#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056
kasperl@chromium.org71affb52009-05-26 05:44:31 +000057namespace v8 {
58namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
60
ager@chromium.org3e875802009-06-29 08:26:34 +000061#define RUNTIME_ASSERT(value) \
62 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64// Cast the given object to a value of the specified type and store
65// it in a variable with the given name. If the object is not of the
66// expected type call IllegalOperation and return.
67#define CONVERT_CHECKED(Type, name, obj) \
68 RUNTIME_ASSERT(obj->Is##Type()); \
69 Type* name = Type::cast(obj);
70
71#define CONVERT_ARG_CHECKED(Type, name, index) \
72 RUNTIME_ASSERT(args[index]->Is##Type()); \
73 Handle<Type> name = args.at<Type>(index);
74
kasper.lundbd3ec4e2008-07-09 11:06:54 +000075// Cast the given object to a boolean and store it in a variable with
76// the given name. If the object is not a boolean call IllegalOperation
77// and return.
78#define CONVERT_BOOLEAN_CHECKED(name, obj) \
79 RUNTIME_ASSERT(obj->IsBoolean()); \
80 bool name = (obj)->IsTrue();
81
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000082// Cast the given object to a Smi and store its value in an int variable
83// with the given name. If the object is not a Smi call IllegalOperation
84// and return.
85#define CONVERT_SMI_CHECKED(name, obj) \
86 RUNTIME_ASSERT(obj->IsSmi()); \
87 int name = Smi::cast(obj)->value();
88
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089// Cast the given object to a double and store it in a variable with
90// the given name. If the object is not a number (as opposed to
91// the number not-a-number) call IllegalOperation and return.
92#define CONVERT_DOUBLE_CHECKED(name, obj) \
93 RUNTIME_ASSERT(obj->IsNumber()); \
94 double name = (obj)->Number();
95
96// Call the specified converter on the object *comand store the result in
97// a variable of the specified type with the given name. If the
98// object is not a Number call IllegalOperation and return.
99#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
100 RUNTIME_ASSERT(obj->IsNumber()); \
101 type name = NumberTo##Type(obj);
102
103// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000104static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105
106
lrn@chromium.org303ada72010-10-27 09:33:13 +0000107MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000108 StackLimitCheck check;
109 if (check.HasOverflowed()) return Top::StackOverflow();
110
lrn@chromium.org303ada72010-10-27 09:33:13 +0000111 Object* result;
112 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
113 if (!maybe_result->ToObject(&result)) return maybe_result;
114 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000115 JSObject* copy = JSObject::cast(result);
116
117 // Deep copy local properties.
118 if (copy->HasFastProperties()) {
119 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000120 for (int i = 0; i < properties->length(); i++) {
121 Object* value = properties->get(i);
122 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000123 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000124 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
125 if (!maybe_result->ToObject(&result)) return maybe_result;
126 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000127 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000128 }
129 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000130 int nof = copy->map()->inobject_properties();
131 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000132 Object* value = copy->InObjectPropertyAt(i);
133 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000134 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000135 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
136 if (!maybe_result->ToObject(&result)) return maybe_result;
137 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000138 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000139 }
140 }
141 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000142 { MaybeObject* maybe_result =
143 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
144 if (!maybe_result->ToObject(&result)) return maybe_result;
145 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 FixedArray* names = FixedArray::cast(result);
147 copy->GetLocalPropertyNames(names, 0);
148 for (int i = 0; i < names->length(); i++) {
149 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 // Only deep copy fields from the object literal expression.
154 // In particular, don't try to copy the length attribute of
155 // an array.
156 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000157 Object* value =
158 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000159 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000160 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
162 if (!maybe_result->ToObject(&result)) return maybe_result;
163 }
164 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000165 // Creating object copy for literals. No strict mode needed.
166 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 if (!maybe_result->ToObject(&result)) return maybe_result;
168 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000169 }
170 }
171 }
172
173 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000174 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000175 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000176 switch (copy->GetElementsKind()) {
177 case JSObject::FAST_ELEMENTS: {
178 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000179 if (elements->map() == Heap::fixed_cow_array_map()) {
180 Counters::cow_arrays_created_runtime.Increment();
181#ifdef DEBUG
182 for (int i = 0; i < elements->length(); i++) {
183 ASSERT(!elements->get(i)->IsJSObject());
184 }
185#endif
186 } else {
187 for (int i = 0; i < elements->length(); i++) {
188 Object* value = elements->get(i);
189 if (value->IsJSObject()) {
190 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000191 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000194 elements->set(i, result);
195 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
197 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000198 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 case JSObject::DICTIONARY_ELEMENTS: {
201 NumberDictionary* element_dictionary = copy->element_dictionary();
202 int capacity = element_dictionary->Capacity();
203 for (int i = 0; i < capacity; i++) {
204 Object* k = element_dictionary->KeyAt(i);
205 if (element_dictionary->IsKey(k)) {
206 Object* value = element_dictionary->ValueAt(i);
207 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000208 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
210 if (!maybe_result->ToObject(&result)) return maybe_result;
211 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000212 element_dictionary->ValueAtPut(i, result);
213 }
214 }
215 }
216 break;
217 }
218 default:
219 UNREACHABLE();
220 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000221 }
222 return copy;
223}
224
225
lrn@chromium.org303ada72010-10-27 09:33:13 +0000226static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000227 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
228 return DeepCopyBoilerplate(boilerplate);
229}
230
231
lrn@chromium.org303ada72010-10-27 09:33:13 +0000232static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000234 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235}
236
237
ager@chromium.org236ad962008-09-25 09:45:57 +0000238static Handle<Map> ComputeObjectLiteralMap(
239 Handle<Context> context,
240 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000241 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000242 int properties_length = constant_properties->length();
243 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000244 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000245 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000246 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000247 for (int p = 0; p != properties_length; p += 2) {
248 Object* key = constant_properties->get(p);
249 uint32_t element_index = 0;
250 if (key->IsSymbol()) {
251 number_of_symbol_keys++;
252 } else if (key->ToArrayIndex(&element_index)) {
253 // An index key does not require space in the property backing store.
254 number_of_properties--;
255 } else {
256 // Bail out as a non-symbol non-index key makes caching impossible.
257 // ASSERT to make sure that the if condition after the loop is false.
258 ASSERT(number_of_symbol_keys != number_of_properties);
259 break;
260 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000262 // If we only have symbols and array indices among keys then we can
263 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000265 if ((number_of_symbol_keys == number_of_properties) &&
266 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 // Create the fixed array with the key.
268 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000269 if (number_of_symbol_keys > 0) {
270 int index = 0;
271 for (int p = 0; p < properties_length; p += 2) {
272 Object* key = constant_properties->get(p);
273 if (key->IsSymbol()) {
274 keys->set(index++, key);
275 }
276 }
277 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000279 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000280 return Factory::ObjectLiteralMapFromCache(context, keys);
281 }
282 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000283 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000284 return Factory::CopyMap(
285 Handle<Map>(context->object_function()->initial_map()),
286 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000287}
288
289
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000290static Handle<Object> CreateLiteralBoilerplate(
291 Handle<FixedArray> literals,
292 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000293
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000294
295static Handle<Object> CreateObjectLiteralBoilerplate(
296 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000297 Handle<FixedArray> constant_properties,
298 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299 // Get the global context from the literals array. This is the
300 // context in which the function was created and we use the object
301 // function from this context to create the object literal. We do
302 // not use the object function from the current global context
303 // because this might be the object function from another context
304 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000305 Handle<Context> context =
306 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
307
308 bool is_result_from_cache;
309 Handle<Map> map = ComputeObjectLiteralMap(context,
310 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000311 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000312
ager@chromium.org236ad962008-09-25 09:45:57 +0000313 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000314
315 // Normalize the elements of the boilerplate to save space if needed.
316 if (!should_have_fast_elements) NormalizeElements(boilerplate);
317
ager@chromium.org32912102009-01-16 10:38:43 +0000318 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000320 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000321 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000322 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323 for (int index = 0; index < length; index +=2) {
324 Handle<Object> key(constant_properties->get(index+0));
325 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000326 if (value->IsFixedArray()) {
327 // The value contains the constant_properties of a
328 // simple object literal.
329 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
330 value = CreateLiteralBoilerplate(literals, array);
331 if (value.is_null()) return value;
332 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000333 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000334 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000335 if (key->IsSymbol()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000336 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
337 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000338 result = SetOwnElement(boilerplate,
339 element_index,
340 value,
341 kNonStrictMode);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000342 } else {
343 Handle<String> name(String::cast(*key));
344 ASSERT(!name->AsArrayIndex(&element_index));
345 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
346 value, NONE);
347 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000348 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349 // Array index (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000350 result = SetOwnElement(boilerplate,
351 element_index,
352 value,
353 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354 } else {
355 // Non-uint32 number.
356 ASSERT(key->IsNumber());
357 double num = key->Number();
358 char arr[100];
359 Vector<char> buffer(arr, ARRAY_SIZE(arr));
360 const char* str = DoubleToCString(num, buffer);
361 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000362 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
363 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000365 // If setting the property on the boilerplate throws an
366 // exception, the exception is converted to an empty handle in
367 // the handle based operations. In that case, we need to
368 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000369 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000370 }
371 }
372
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000373 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000374}
375
376
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000377static Handle<Object> CreateArrayLiteralBoilerplate(
378 Handle<FixedArray> literals,
379 Handle<FixedArray> elements) {
380 // Create the JSArray.
381 Handle<JSFunction> constructor(
382 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
383 Handle<Object> object = Factory::NewJSObject(constructor);
384
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000385 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
386 Handle<FixedArray> copied_elements =
387 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000388
389 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000390 if (is_cow) {
391#ifdef DEBUG
392 // Copy-on-write arrays must be shallow (and simple).
393 for (int i = 0; i < content->length(); i++) {
394 ASSERT(!content->get(i)->IsFixedArray());
395 }
396#endif
397 } else {
398 for (int i = 0; i < content->length(); i++) {
399 if (content->get(i)->IsFixedArray()) {
400 // The value contains the constant_properties of a
401 // simple object literal.
402 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
403 Handle<Object> result =
404 CreateLiteralBoilerplate(literals, fa);
405 if (result.is_null()) return result;
406 content->set(i, *result);
407 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000408 }
409 }
410
411 // Set the elements.
412 Handle<JSArray>::cast(object)->SetContent(*content);
413 return object;
414}
415
416
417static Handle<Object> CreateLiteralBoilerplate(
418 Handle<FixedArray> literals,
419 Handle<FixedArray> array) {
420 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
421 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000422 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
423 return CreateObjectLiteralBoilerplate(literals, elements, true);
424 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
425 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000426 case CompileTimeValue::ARRAY_LITERAL:
427 return CreateArrayLiteralBoilerplate(literals, elements);
428 default:
429 UNREACHABLE();
430 return Handle<Object>::null();
431 }
432}
433
434
lrn@chromium.org303ada72010-10-27 09:33:13 +0000435static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000436 // Takes a FixedArray of elements containing the literal elements of
437 // the array literal and produces JSArray with those elements.
438 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000439 // which contains the context from which to get the Array function
440 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000441 HandleScope scope;
442 ASSERT(args.length() == 3);
443 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
444 CONVERT_SMI_CHECKED(literals_index, args[1]);
445 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000446
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000447 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
448 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000450 // Update the functions literal and return the boilerplate.
451 literals->set(literals_index, *object);
452 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000453}
454
455
lrn@chromium.org303ada72010-10-27 09:33:13 +0000456static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000457 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000458 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000459 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
460 CONVERT_SMI_CHECKED(literals_index, args[1]);
461 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000462 CONVERT_SMI_CHECKED(fast_elements, args[3]);
463 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000464
465 // Check if boilerplate exists. If not, create it first.
466 Handle<Object> boilerplate(literals->get(literals_index));
467 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000468 boilerplate = CreateObjectLiteralBoilerplate(literals,
469 constant_properties,
470 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000471 if (boilerplate.is_null()) return Failure::Exception();
472 // Update the functions literal and return the boilerplate.
473 literals->set(literals_index, *boilerplate);
474 }
475 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
476}
477
478
lrn@chromium.org303ada72010-10-27 09:33:13 +0000479static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000480 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000481 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000482 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
483 CONVERT_SMI_CHECKED(literals_index, args[1]);
484 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000485 CONVERT_SMI_CHECKED(fast_elements, args[3]);
486 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000487
488 // Check if boilerplate exists. If not, create it first.
489 Handle<Object> boilerplate(literals->get(literals_index));
490 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000491 boilerplate = CreateObjectLiteralBoilerplate(literals,
492 constant_properties,
493 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000494 if (boilerplate.is_null()) return Failure::Exception();
495 // Update the functions literal and return the boilerplate.
496 literals->set(literals_index, *boilerplate);
497 }
498 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
499}
500
501
lrn@chromium.org303ada72010-10-27 09:33:13 +0000502static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000503 HandleScope scope;
504 ASSERT(args.length() == 3);
505 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
506 CONVERT_SMI_CHECKED(literals_index, args[1]);
507 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
508
509 // Check if boilerplate exists. If not, create it first.
510 Handle<Object> boilerplate(literals->get(literals_index));
511 if (*boilerplate == Heap::undefined_value()) {
512 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
513 if (boilerplate.is_null()) return Failure::Exception();
514 // Update the functions literal and return the boilerplate.
515 literals->set(literals_index, *boilerplate);
516 }
517 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
518}
519
520
lrn@chromium.org303ada72010-10-27 09:33:13 +0000521static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000522 HandleScope scope;
523 ASSERT(args.length() == 3);
524 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
525 CONVERT_SMI_CHECKED(literals_index, args[1]);
526 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
527
528 // Check if boilerplate exists. If not, create it first.
529 Handle<Object> boilerplate(literals->get(literals_index));
530 if (*boilerplate == Heap::undefined_value()) {
531 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
532 if (boilerplate.is_null()) return Failure::Exception();
533 // Update the functions literal and return the boilerplate.
534 literals->set(literals_index, *boilerplate);
535 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000536 if (JSObject::cast(*boilerplate)->elements()->map() ==
537 Heap::fixed_cow_array_map()) {
538 Counters::cow_arrays_created_runtime.Increment();
539 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
541}
542
543
lrn@chromium.org303ada72010-10-27 09:33:13 +0000544static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000545 ASSERT(args.length() == 2);
546 CONVERT_CHECKED(String, key, args[0]);
547 Object* value = args[1];
548 // Create a catch context extension object.
549 JSFunction* constructor =
550 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000551 Object* object;
552 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
553 if (!maybe_object->ToObject(&object)) return maybe_object;
554 }
ager@chromium.org32912102009-01-16 10:38:43 +0000555 // Assign the exception value to the catch variable and make sure
556 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000557 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000558 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
559 JSObject::cast(object)->SetProperty(
560 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000561 if (!maybe_value->ToObject(&value)) return maybe_value;
562 }
ager@chromium.org32912102009-01-16 10:38:43 +0000563 return object;
564}
565
566
lrn@chromium.org303ada72010-10-27 09:33:13 +0000567static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568 NoHandleAllocation ha;
569 ASSERT(args.length() == 1);
570 Object* obj = args[0];
571 if (!obj->IsJSObject()) return Heap::null_value();
572 return JSObject::cast(obj)->class_name();
573}
574
ager@chromium.org7c537e22008-10-16 08:43:32 +0000575
lrn@chromium.org303ada72010-10-27 09:33:13 +0000576static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000577 NoHandleAllocation ha;
578 ASSERT(args.length() == 2);
579 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
580 Object* O = args[0];
581 Object* V = args[1];
582 while (true) {
583 Object* prototype = V->GetPrototype();
584 if (prototype->IsNull()) return Heap::false_value();
585 if (O == prototype) return Heap::true_value();
586 V = prototype;
587 }
588}
589
590
ager@chromium.org9085a012009-05-11 19:22:57 +0000591// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000592static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000593 NoHandleAllocation ha;
594 ASSERT(args.length() == 2);
595 CONVERT_CHECKED(JSObject, jsobject, args[0]);
596 CONVERT_CHECKED(JSObject, proto, args[1]);
597
598 // Sanity checks. The old prototype (that we are replacing) could
599 // theoretically be null, but if it is not null then check that we
600 // didn't already install a hidden prototype here.
601 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
602 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
603 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
604
605 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000606 Object* map_or_failure;
607 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
608 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
609 return maybe_map_or_failure;
610 }
611 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000612 Map* new_proto_map = Map::cast(map_or_failure);
613
lrn@chromium.org303ada72010-10-27 09:33:13 +0000614 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
615 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
616 return maybe_map_or_failure;
617 }
618 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000619 Map* new_map = Map::cast(map_or_failure);
620
621 // Set proto's prototype to be the old prototype of the object.
622 new_proto_map->set_prototype(jsobject->GetPrototype());
623 proto->set_map(new_proto_map);
624 new_proto_map->set_is_hidden_prototype();
625
626 // Set the object's prototype to proto.
627 new_map->set_prototype(proto);
628 jsobject->set_map(new_map);
629
630 return Heap::undefined_value();
631}
632
633
lrn@chromium.org303ada72010-10-27 09:33:13 +0000634static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000635 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000636 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000637 JavaScriptFrameIterator it;
638 return Heap::ToBoolean(it.frame()->IsConstructor());
639}
640
641
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000642// Recursively traverses hidden prototypes if property is not found
643static void GetOwnPropertyImplementation(JSObject* obj,
644 String* name,
645 LookupResult* result) {
646 obj->LocalLookupRealNamedProperty(name, result);
647
648 if (!result->IsProperty()) {
649 Object* proto = obj->GetPrototype();
650 if (proto->IsJSObject() &&
651 JSObject::cast(proto)->map()->is_hidden_prototype())
652 GetOwnPropertyImplementation(JSObject::cast(proto),
653 name, result);
654 }
655}
656
657
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000658static bool CheckAccessException(LookupResult* result,
659 v8::AccessType access_type) {
660 if (result->type() == CALLBACKS) {
661 Object* callback = result->GetCallbackObject();
662 if (callback->IsAccessorInfo()) {
663 AccessorInfo* info = AccessorInfo::cast(callback);
664 bool can_access =
665 (access_type == v8::ACCESS_HAS &&
666 (info->all_can_read() || info->all_can_write())) ||
667 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
668 (access_type == v8::ACCESS_SET && info->all_can_write());
669 return can_access;
670 }
671 }
672
673 return false;
674}
675
676
677static bool CheckAccess(JSObject* obj,
678 String* name,
679 LookupResult* result,
680 v8::AccessType access_type) {
681 ASSERT(result->IsProperty());
682
683 JSObject* holder = result->holder();
684 JSObject* current = obj;
685 while (true) {
686 if (current->IsAccessCheckNeeded() &&
687 !Top::MayNamedAccess(current, name, access_type)) {
688 // Access check callback denied the access, but some properties
689 // can have a special permissions which override callbacks descision
690 // (currently see v8::AccessControl).
691 break;
692 }
693
694 if (current == holder) {
695 return true;
696 }
697
698 current = JSObject::cast(current->GetPrototype());
699 }
700
701 // API callbacks can have per callback access exceptions.
702 switch (result->type()) {
703 case CALLBACKS: {
704 if (CheckAccessException(result, access_type)) {
705 return true;
706 }
707 break;
708 }
709 case INTERCEPTOR: {
710 // If the object has an interceptor, try real named properties.
711 // Overwrite the result to fetch the correct property later.
712 holder->LookupRealNamedProperty(name, result);
713 if (result->IsProperty()) {
714 if (CheckAccessException(result, access_type)) {
715 return true;
716 }
717 }
718 break;
719 }
720 default:
721 break;
722 }
723
724 Top::ReportFailedAccessCheck(current, access_type);
725 return false;
726}
727
728
729// TODO(1095): we should traverse hidden prototype hierachy as well.
730static bool CheckElementAccess(JSObject* obj,
731 uint32_t index,
732 v8::AccessType access_type) {
733 if (obj->IsAccessCheckNeeded() &&
734 !Top::MayIndexedAccess(obj, index, access_type)) {
735 return false;
736 }
737
738 return true;
739}
740
741
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000742// Enumerator used as indices into the array returned from GetOwnProperty
743enum PropertyDescriptorIndices {
744 IS_ACCESSOR_INDEX,
745 VALUE_INDEX,
746 GETTER_INDEX,
747 SETTER_INDEX,
748 WRITABLE_INDEX,
749 ENUMERABLE_INDEX,
750 CONFIGURABLE_INDEX,
751 DESCRIPTOR_SIZE
752};
753
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000754// Returns an array with the property description:
755// if args[1] is not a property on args[0]
756// returns undefined
757// if args[1] is a data property on args[0]
758// [false, value, Writeable, Enumerable, Configurable]
759// if args[1] is an accessor on args[0]
760// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000761static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000762 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000763 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000764 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000765 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
766 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000767 CONVERT_ARG_CHECKED(JSObject, obj, 0);
768 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000769
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000770 // This could be an element.
771 uint32_t index;
772 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000773 switch (obj->HasLocalElement(index)) {
774 case JSObject::UNDEFINED_ELEMENT:
775 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000776
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000777 case JSObject::STRING_CHARACTER_ELEMENT: {
778 // Special handling of string objects according to ECMAScript 5
779 // 15.5.5.2. Note that this might be a string object with elements
780 // other than the actual string value. This is covered by the
781 // subsequent cases.
782 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
783 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000784 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000785
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000786 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
787 elms->set(VALUE_INDEX, *substr);
788 elms->set(WRITABLE_INDEX, Heap::false_value());
789 elms->set(ENUMERABLE_INDEX, Heap::false_value());
790 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
791 return *desc;
792 }
793
794 case JSObject::INTERCEPTED_ELEMENT:
795 case JSObject::FAST_ELEMENT: {
796 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000797 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000798 RETURN_IF_EMPTY_HANDLE(value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000799 elms->set(VALUE_INDEX, *value);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000800 elms->set(WRITABLE_INDEX, Heap::true_value());
801 elms->set(ENUMERABLE_INDEX, Heap::true_value());
802 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
803 return *desc;
804 }
805
806 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000807 Handle<JSObject> holder = obj;
808 if (obj->IsJSGlobalProxy()) {
809 Object* proto = obj->GetPrototype();
810 if (proto->IsNull()) return Heap::undefined_value();
811 ASSERT(proto->IsJSGlobalObject());
812 holder = Handle<JSObject>(JSObject::cast(proto));
813 }
814 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000815 int entry = dictionary->FindEntry(index);
816 ASSERT(entry != NumberDictionary::kNotFound);
817 PropertyDetails details = dictionary->DetailsAt(entry);
818 switch (details.type()) {
819 case CALLBACKS: {
820 // This is an accessor property with getter and/or setter.
821 FixedArray* callbacks =
822 FixedArray::cast(dictionary->ValueAt(entry));
823 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000824 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
825 elms->set(GETTER_INDEX, callbacks->get(0));
826 }
827 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
828 elms->set(SETTER_INDEX, callbacks->get(1));
829 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000830 break;
831 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000832 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000833 // This is a data property.
834 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000835 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000836 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000837 elms->set(VALUE_INDEX, *value);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000838 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
839 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000840 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000841 default:
842 UNREACHABLE();
843 break;
844 }
845 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
846 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
847 return *desc;
848 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000849 }
850 }
851
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000852 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000853 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000854
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000855 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000856 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000857 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000858
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000859 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
860 return Heap::false_value();
861 }
862
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000863 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
864 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000865
866 bool is_js_accessor = (result.type() == CALLBACKS) &&
867 (result.GetCallbackObject()->IsFixedArray());
868
869 if (is_js_accessor) {
870 // __defineGetter__/__defineSetter__ callback.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000871 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000872
873 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
874 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
875 elms->set(GETTER_INDEX, structure->get(0));
876 }
877 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
878 elms->set(SETTER_INDEX, structure->get(1));
879 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000880 } else {
881 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
882 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
883
884 PropertyAttributes attrs;
885 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000886 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000887 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
888 if (!maybe_value->ToObject(&value)) return maybe_value;
889 }
890 elms->set(VALUE_INDEX, value);
891 }
892
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000893 return *desc;
894}
895
896
lrn@chromium.org303ada72010-10-27 09:33:13 +0000897static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000898 ASSERT(args.length() == 1);
899 CONVERT_CHECKED(JSObject, obj, args[0]);
900 return obj->PreventExtensions();
901}
902
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000903
lrn@chromium.org303ada72010-10-27 09:33:13 +0000904static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000905 ASSERT(args.length() == 1);
906 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000907 if (obj->IsJSGlobalProxy()) {
908 Object* proto = obj->GetPrototype();
909 if (proto->IsNull()) return Heap::false_value();
910 ASSERT(proto->IsJSGlobalObject());
911 obj = JSObject::cast(proto);
912 }
913 return obj->map()->is_extensible() ? Heap::true_value()
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000914 : Heap::false_value();
915}
916
917
lrn@chromium.org303ada72010-10-27 09:33:13 +0000918static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000919 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000920 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000921 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
922 CONVERT_ARG_CHECKED(String, pattern, 1);
923 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000924 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
925 if (result.is_null()) return Failure::Exception();
926 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927}
928
929
lrn@chromium.org303ada72010-10-27 09:33:13 +0000930static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931 HandleScope scope;
932 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000933 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934 return *Factory::CreateApiFunction(data);
935}
936
937
lrn@chromium.org303ada72010-10-27 09:33:13 +0000938static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000939 ASSERT(args.length() == 1);
940 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000941 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942 return Heap::ToBoolean(result);
943}
944
945
lrn@chromium.org303ada72010-10-27 09:33:13 +0000946static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000947 ASSERT(args.length() == 2);
948 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000949 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000950 int index = field->value();
951 int offset = index * kPointerSize + HeapObject::kHeaderSize;
952 InstanceType type = templ->map()->instance_type();
953 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
954 type == OBJECT_TEMPLATE_INFO_TYPE);
955 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000956 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000957 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
958 } else {
959 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
960 }
961 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000962}
963
964
lrn@chromium.org303ada72010-10-27 09:33:13 +0000965static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000966 ASSERT(args.length() == 1);
967 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000968 Map* old_map = object->map();
969 bool needs_access_checks = old_map->is_access_check_needed();
970 if (needs_access_checks) {
971 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000972 Object* new_map;
973 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
974 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
975 }
ager@chromium.org32912102009-01-16 10:38:43 +0000976
977 Map::cast(new_map)->set_is_access_check_needed(false);
978 object->set_map(Map::cast(new_map));
979 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000980 return needs_access_checks ? Heap::true_value() : Heap::false_value();
981}
982
983
lrn@chromium.org303ada72010-10-27 09:33:13 +0000984static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000985 ASSERT(args.length() == 1);
986 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000987 Map* old_map = object->map();
988 if (!old_map->is_access_check_needed()) {
989 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000990 Object* new_map;
991 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
992 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
993 }
ager@chromium.org32912102009-01-16 10:38:43 +0000994
995 Map::cast(new_map)->set_is_access_check_needed(true);
996 object->set_map(Map::cast(new_map));
997 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000998 return Heap::undefined_value();
999}
1000
1001
lrn@chromium.org303ada72010-10-27 09:33:13 +00001002static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 HandleScope scope;
1004 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
1005 Handle<Object> args[2] = { type_handle, name };
1006 Handle<Object> error =
1007 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
1008 return Top::Throw(*error);
1009}
1010
1011
lrn@chromium.org303ada72010-10-27 09:33:13 +00001012static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001013 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014 HandleScope scope;
1015 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
1016
ager@chromium.org3811b432009-10-28 14:53:37 +00001017 Handle<Context> context = args.at<Context>(0);
1018 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001020 StrictModeFlag strict_mode =
1021 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1022 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023
1024 // Compute the property attributes. According to ECMA-262, section
1025 // 13, page 71, the property must be read-only and
1026 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1027 // property as read-only, so we don't either.
1028 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1029
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001030 // Traverse the name/value pairs and set the properties.
1031 int length = pairs->length();
1032 for (int i = 0; i < length; i += 2) {
1033 HandleScope scope;
1034 Handle<String> name(String::cast(pairs->get(i)));
1035 Handle<Object> value(pairs->get(i + 1));
1036
1037 // We have to declare a global const property. To capture we only
1038 // assign to it when evaluating the assignment for "const x =
1039 // <expr>" the initial value is the hole.
1040 bool is_const_property = value->IsTheHole();
1041
1042 if (value->IsUndefined() || is_const_property) {
1043 // Lookup the property in the global object, and don't set the
1044 // value of the variable if the property is already there.
1045 LookupResult lookup;
1046 global->Lookup(*name, &lookup);
1047 if (lookup.IsProperty()) {
1048 // Determine if the property is local by comparing the holder
1049 // against the global object. The information will be used to
1050 // avoid throwing re-declaration errors when declaring
1051 // variables or constants that exist in the prototype chain.
1052 bool is_local = (*global == lookup.holder());
1053 // Get the property attributes and determine if the property is
1054 // read-only.
1055 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1056 bool is_read_only = (attributes & READ_ONLY) != 0;
1057 if (lookup.type() == INTERCEPTOR) {
1058 // If the interceptor says the property is there, we
1059 // just return undefined without overwriting the property.
1060 // Otherwise, we continue to setting the property.
1061 if (attributes != ABSENT) {
1062 // Check if the existing property conflicts with regards to const.
1063 if (is_local && (is_read_only || is_const_property)) {
1064 const char* type = (is_read_only) ? "const" : "var";
1065 return ThrowRedeclarationError(type, name);
1066 };
1067 // The property already exists without conflicting: Go to
1068 // the next declaration.
1069 continue;
1070 }
1071 // Fall-through and introduce the absent property by using
1072 // SetProperty.
1073 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001074 // For const properties, we treat a callback with this name
1075 // even in the prototype as a conflicting declaration.
1076 if (is_const_property && (lookup.type() == CALLBACKS)) {
1077 return ThrowRedeclarationError("const", name);
1078 }
1079 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080 if (is_local && (is_read_only || is_const_property)) {
1081 const char* type = (is_read_only) ? "const" : "var";
1082 return ThrowRedeclarationError(type, name);
1083 }
1084 // The property already exists without conflicting: Go to
1085 // the next declaration.
1086 continue;
1087 }
1088 }
1089 } else {
1090 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001091 Handle<SharedFunctionInfo> shared =
1092 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001094 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001095 value = function;
1096 }
1097
1098 LookupResult lookup;
1099 global->LocalLookup(*name, &lookup);
1100
1101 PropertyAttributes attributes = is_const_property
1102 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1103 : base;
1104
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001105 // There's a local property that we need to overwrite because
1106 // we're either declaring a function or there's an interceptor
1107 // that claims the property is absent.
1108 //
1109 // Check for conflicting re-declarations. We cannot have
1110 // conflicting types in case of intercepted properties because
1111 // they are absent.
1112 if (lookup.IsProperty() &&
1113 (lookup.type() != INTERCEPTOR) &&
1114 (lookup.IsReadOnly() || is_const_property)) {
1115 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
1116 return ThrowRedeclarationError(type, name);
1117 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001119 // Safari does not allow the invocation of callback setters for
1120 // function declarations. To mimic this behavior, we do not allow
1121 // the invocation of setters for function values. This makes a
1122 // difference for global functions with the same names as event
1123 // handlers such as "function onload() {}". Firefox does call the
1124 // onload setter in those case and Safari does not. We follow
1125 // Safari for compatibility.
1126 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001127 // Do not change DONT_DELETE to false from true.
1128 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1129 attributes = static_cast<PropertyAttributes>(
1130 attributes | (lookup.GetAttributes() & DONT_DELETE));
1131 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001132 RETURN_IF_EMPTY_HANDLE(SetLocalPropertyIgnoreAttributes(global,
1133 name,
1134 value,
1135 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001136 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001137 RETURN_IF_EMPTY_HANDLE(SetProperty(global,
1138 name,
1139 value,
1140 attributes,
1141 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001142 }
1143 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001144
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001145 ASSERT(!Top::has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146 return Heap::undefined_value();
1147}
1148
1149
lrn@chromium.org303ada72010-10-27 09:33:13 +00001150static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001152 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001153
ager@chromium.org7c537e22008-10-16 08:43:32 +00001154 CONVERT_ARG_CHECKED(Context, context, 0);
1155 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001156 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001157 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001158 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001159 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001160
1161 // Declarations are always done in the function context.
1162 context = Handle<Context>(context->fcontext());
1163
1164 int index;
1165 PropertyAttributes attributes;
1166 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001167 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 context->Lookup(name, flags, &index, &attributes);
1169
1170 if (attributes != ABSENT) {
1171 // The name was declared before; check for conflicting
1172 // re-declarations: This is similar to the code in parser.cc in
1173 // the AstBuildingParser::Declare function.
1174 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1175 // Functions are not read-only.
1176 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1177 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1178 return ThrowRedeclarationError(type, name);
1179 }
1180
1181 // Initialize it if necessary.
1182 if (*initial_value != NULL) {
1183 if (index >= 0) {
1184 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001185 // the function context or the arguments object.
1186 if (holder->IsContext()) {
1187 ASSERT(holder.is_identical_to(context));
1188 if (((attributes & READ_ONLY) == 0) ||
1189 context->get(index)->IsTheHole()) {
1190 context->set(index, *initial_value);
1191 }
1192 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001193 // The holder is an arguments object.
1194 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001195 Handle<Object> result = SetElement(arguments, index, initial_value,
1196 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001197 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198 }
1199 } else {
1200 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001201 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001202 RETURN_IF_EMPTY_HANDLE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001203 SetProperty(context_ext, name, initial_value,
1204 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 }
1206 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001207
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001208 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001209 // The property is not in the function context. It needs to be
1210 // "declared" in the function context's extension context, or in the
1211 // global context.
1212 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001213 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001214 // The function context's extension context exists - use it.
1215 context_ext = Handle<JSObject>(context->extension());
1216 } else {
1217 // The function context's extension context does not exists - allocate
1218 // it.
1219 context_ext = Factory::NewJSObject(Top::context_extension_function());
1220 // And store it in the extension slot.
1221 context->set_extension(*context_ext);
1222 }
1223 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001224
ager@chromium.org7c537e22008-10-16 08:43:32 +00001225 // Declare the property by setting it to the initial value if provided,
1226 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1227 // constant declarations).
1228 ASSERT(!context_ext->HasLocalProperty(*name));
1229 Handle<Object> value(Heap::undefined_value());
1230 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001231 // Declaring a const context slot is a conflicting declaration if
1232 // there is a callback with that name in a prototype. It is
1233 // allowed to introduce const variables in
1234 // JSContextExtensionObjects. They are treated specially in
1235 // SetProperty and no setters are invoked for those since they are
1236 // not real JSObjects.
1237 if (initial_value->IsTheHole() &&
1238 !context_ext->IsJSContextExtensionObject()) {
1239 LookupResult lookup;
1240 context_ext->Lookup(*name, &lookup);
1241 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
1242 return ThrowRedeclarationError("const", name);
1243 }
1244 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001245 RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, mode,
1246 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001247 }
1248
1249 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001250}
1251
1252
lrn@chromium.org303ada72010-10-27 09:33:13 +00001253static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001255 // args[0] == name
1256 // args[1] == strict_mode
1257 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258
1259 // Determine if we need to assign to the variable if it already
1260 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001261 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1262 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263
1264 CONVERT_ARG_CHECKED(String, name, 0);
1265 GlobalObject* global = Top::context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001266 RUNTIME_ASSERT(args[1]->IsSmi());
1267 StrictModeFlag strict_mode =
1268 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1269 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270
1271 // According to ECMA-262, section 12.2, page 62, the property must
1272 // not be deletable.
1273 PropertyAttributes attributes = DONT_DELETE;
1274
1275 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001276 // there, there is a property with this name in the prototype chain.
1277 // We follow Safari and Firefox behavior and only set the property
1278 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001279 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001280 // Note that objects can have hidden prototypes, so we need to traverse
1281 // the whole chain of hidden prototypes to do a 'local' lookup.
1282 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001284 while (true) {
1285 real_holder->LocalLookup(*name, &lookup);
1286 if (lookup.IsProperty()) {
1287 // Determine if this is a redeclaration of something read-only.
1288 if (lookup.IsReadOnly()) {
1289 // If we found readonly property on one of hidden prototypes,
1290 // just shadow it.
1291 if (real_holder != Top::context()->global()) break;
1292 return ThrowRedeclarationError("const", name);
1293 }
1294
1295 // Determine if this is a redeclaration of an intercepted read-only
1296 // property and figure out if the property exists at all.
1297 bool found = true;
1298 PropertyType type = lookup.type();
1299 if (type == INTERCEPTOR) {
1300 HandleScope handle_scope;
1301 Handle<JSObject> holder(real_holder);
1302 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1303 real_holder = *holder;
1304 if (intercepted == ABSENT) {
1305 // The interceptor claims the property isn't there. We need to
1306 // make sure to introduce it.
1307 found = false;
1308 } else if ((intercepted & READ_ONLY) != 0) {
1309 // The property is present, but read-only. Since we're trying to
1310 // overwrite it with a variable declaration we must throw a
1311 // re-declaration error. However if we found readonly property
1312 // on one of hidden prototypes, just shadow it.
1313 if (real_holder != Top::context()->global()) break;
1314 return ThrowRedeclarationError("const", name);
1315 }
1316 }
1317
1318 if (found && !assign) {
1319 // The global property is there and we're not assigning any value
1320 // to it. Just return.
1321 return Heap::undefined_value();
1322 }
1323
1324 // Assign the value (or undefined) to the property.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001325 Object* value = (assign) ? args[2] : Heap::undefined_value();
1326 return real_holder->SetProperty(
1327 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001328 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001329
1330 Object* proto = real_holder->GetPrototype();
1331 if (!proto->IsJSObject())
1332 break;
1333
1334 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1335 break;
1336
1337 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 }
1339
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001340 global = Top::context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001341 if (assign) {
1342 return global->SetProperty(*name, args[2], attributes, strict_mode);
1343 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001344 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345}
1346
1347
lrn@chromium.org303ada72010-10-27 09:33:13 +00001348static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001349 // All constants are declared with an initial value. The name
1350 // of the constant is the first argument and the initial value
1351 // is the second.
1352 RUNTIME_ASSERT(args.length() == 2);
1353 CONVERT_ARG_CHECKED(String, name, 0);
1354 Handle<Object> value = args.at<Object>(1);
1355
1356 // Get the current global object from top.
1357 GlobalObject* global = Top::context()->global();
1358
1359 // According to ECMA-262, section 12.2, page 62, the property must
1360 // not be deletable. Since it's a const, it must be READ_ONLY too.
1361 PropertyAttributes attributes =
1362 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1363
1364 // Lookup the property locally in the global object. If it isn't
1365 // there, we add the property and take special precautions to always
1366 // add it as a local property even in case of callbacks in the
1367 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001368 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369 LookupResult lookup;
1370 global->LocalLookup(*name, &lookup);
1371 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001372 return global->SetLocalPropertyIgnoreAttributes(*name,
1373 *value,
1374 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001375 }
1376
1377 // Determine if this is a redeclaration of something not
1378 // read-only. In case the result is hidden behind an interceptor we
1379 // need to ask it for the property attributes.
1380 if (!lookup.IsReadOnly()) {
1381 if (lookup.type() != INTERCEPTOR) {
1382 return ThrowRedeclarationError("var", name);
1383 }
1384
1385 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1386
1387 // Throw re-declaration error if the intercepted property is present
1388 // but not read-only.
1389 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1390 return ThrowRedeclarationError("var", name);
1391 }
1392
1393 // Restore global object from context (in case of GC) and continue
1394 // with setting the value because the property is either absent or
1395 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001396 HandleScope handle_scope;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001397 Handle<GlobalObject> global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001399 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400 // property through an interceptor and only do it if it's
1401 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001402 // Passing non-strict mode because the property is writable.
1403 RETURN_IF_EMPTY_HANDLE(SetProperty(global,
1404 name,
1405 value,
1406 attributes,
1407 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001408 return *value;
1409 }
1410
1411 // Set the value, but only we're assigning the initial value to a
1412 // constant. For now, we determine this by checking if the
1413 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001414 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415 PropertyType type = lookup.type();
1416 if (type == FIELD) {
1417 FixedArray* properties = global->properties();
1418 int index = lookup.GetFieldIndex();
1419 if (properties->get(index)->IsTheHole()) {
1420 properties->set(index, *value);
1421 }
1422 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001423 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1424 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425 }
1426 } else {
1427 // Ignore re-initialization of constants that have already been
1428 // assigned a function value.
1429 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1430 }
1431
1432 // Use the set value as the result of the operation.
1433 return *value;
1434}
1435
1436
lrn@chromium.org303ada72010-10-27 09:33:13 +00001437static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001438 HandleScope scope;
1439 ASSERT(args.length() == 3);
1440
1441 Handle<Object> value(args[0]);
1442 ASSERT(!value->IsTheHole());
1443 CONVERT_ARG_CHECKED(Context, context, 1);
1444 Handle<String> name(String::cast(args[2]));
1445
1446 // Initializations are always done in the function context.
1447 context = Handle<Context>(context->fcontext());
1448
1449 int index;
1450 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001451 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001452 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001453 context->Lookup(name, flags, &index, &attributes);
1454
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001455 // In most situations, the property introduced by the const
1456 // declaration should be present in the context extension object.
1457 // However, because declaration and initialization are separate, the
1458 // property might have been deleted (if it was introduced by eval)
1459 // before we reach the initialization point.
1460 //
1461 // Example:
1462 //
1463 // function f() { eval("delete x; const x;"); }
1464 //
1465 // In that case, the initialization behaves like a normal assignment
1466 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001468 // Property was found in a context.
1469 if (holder->IsContext()) {
1470 // The holder cannot be the function context. If it is, there
1471 // should have been a const redeclaration error when declaring
1472 // the const property.
1473 ASSERT(!holder.is_identical_to(context));
1474 if ((attributes & READ_ONLY) == 0) {
1475 Handle<Context>::cast(holder)->set(index, *value);
1476 }
1477 } else {
1478 // The holder is an arguments object.
1479 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001480 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001481 RETURN_IF_EMPTY_HANDLE(
1482 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 }
1484 return *value;
1485 }
1486
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001487 // The property could not be found, we introduce it in the global
1488 // context.
1489 if (attributes == ABSENT) {
1490 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001491 // Strict mode not needed (const disallowed in strict mode).
1492 RETURN_IF_EMPTY_HANDLE(
1493 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001494 return *value;
1495 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001496
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001497 // The property was present in a context extension object.
1498 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001499
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001500 if (*context_ext == context->extension()) {
1501 // This is the property that was introduced by the const
1502 // declaration. Set it if it hasn't been set before. NOTE: We
1503 // cannot use GetProperty() to get the current value as it
1504 // 'unholes' the value.
1505 LookupResult lookup;
1506 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1507 ASSERT(lookup.IsProperty()); // the property was declared
1508 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1509
1510 PropertyType type = lookup.type();
1511 if (type == FIELD) {
1512 FixedArray* properties = context_ext->properties();
1513 int index = lookup.GetFieldIndex();
1514 if (properties->get(index)->IsTheHole()) {
1515 properties->set(index, *value);
1516 }
1517 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001518 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1519 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001520 }
1521 } else {
1522 // We should not reach here. Any real, named property should be
1523 // either a field or a dictionary slot.
1524 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001525 }
1526 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001527 // The property was found in a different context extension object.
1528 // Set it if it is not a read-only property.
1529 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001530 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001531 RETURN_IF_EMPTY_HANDLE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001532 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001533 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001535
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536 return *value;
1537}
1538
1539
lrn@chromium.org303ada72010-10-27 09:33:13 +00001540static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001541 Arguments args) {
1542 HandleScope scope;
1543 ASSERT(args.length() == 2);
1544 CONVERT_ARG_CHECKED(JSObject, object, 0);
1545 CONVERT_SMI_CHECKED(properties, args[1]);
1546 if (object->HasFastProperties()) {
1547 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1548 }
1549 return *object;
1550}
1551
1552
lrn@chromium.org303ada72010-10-27 09:33:13 +00001553static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001555 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001556 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1557 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001558 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001559 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001560 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001561 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001562 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001563 RUNTIME_ASSERT(index >= 0);
1564 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001565 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001566 Handle<Object> result = RegExpImpl::Exec(regexp,
1567 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001568 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001569 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001570 if (result.is_null()) return Failure::Exception();
1571 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572}
1573
1574
lrn@chromium.org303ada72010-10-27 09:33:13 +00001575static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001576 ASSERT(args.length() == 3);
1577 CONVERT_SMI_CHECKED(elements_count, args[0]);
1578 if (elements_count > JSArray::kMaxFastElementsLength) {
1579 return Top::ThrowIllegalOperation();
1580 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001581 Object* new_object;
1582 { MaybeObject* maybe_new_object =
1583 Heap::AllocateFixedArrayWithHoles(elements_count);
1584 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1585 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001586 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001587 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1588 NEW_SPACE,
1589 OLD_POINTER_SPACE);
1590 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1591 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001592 {
1593 AssertNoAllocation no_gc;
1594 HandleScope scope;
1595 reinterpret_cast<HeapObject*>(new_object)->
1596 set_map(Top::global_context()->regexp_result_map());
1597 }
1598 JSArray* array = JSArray::cast(new_object);
1599 array->set_properties(Heap::empty_fixed_array());
1600 array->set_elements(elements);
1601 array->set_length(Smi::FromInt(elements_count));
1602 // Write in-object properties after the length of the array.
1603 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1604 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1605 return array;
1606}
1607
1608
lrn@chromium.org303ada72010-10-27 09:33:13 +00001609static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001610 AssertNoAllocation no_alloc;
1611 ASSERT(args.length() == 5);
1612 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1613 CONVERT_CHECKED(String, source, args[1]);
1614
1615 Object* global = args[2];
1616 if (!global->IsTrue()) global = Heap::false_value();
1617
1618 Object* ignoreCase = args[3];
1619 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1620
1621 Object* multiline = args[4];
1622 if (!multiline->IsTrue()) multiline = Heap::false_value();
1623
1624 Map* map = regexp->map();
1625 Object* constructor = map->constructor();
1626 if (constructor->IsJSFunction() &&
1627 JSFunction::cast(constructor)->initial_map() == map) {
1628 // If we still have the original map, set in-object properties directly.
1629 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1630 // TODO(lrn): Consider skipping write barrier on booleans as well.
1631 // Both true and false should be in oldspace at all times.
1632 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1633 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1634 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1635 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1636 Smi::FromInt(0),
1637 SKIP_WRITE_BARRIER);
1638 return regexp;
1639 }
1640
lrn@chromium.org303ada72010-10-27 09:33:13 +00001641 // Map has changed, so use generic, but slower, method. Since these
1642 // properties were all added as DONT_DELETE they must be present and
1643 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001644 PropertyAttributes final =
1645 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1646 PropertyAttributes writable =
1647 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001648 MaybeObject* result;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001649 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
1650 source,
1651 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001652 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001653 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
1654 global,
1655 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001656 ASSERT(!result->IsFailure());
1657 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001658 regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
1659 ignoreCase,
1660 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001661 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001662 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
1663 multiline,
1664 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001665 ASSERT(!result->IsFailure());
1666 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001667 regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
1668 Smi::FromInt(0),
1669 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001670 ASSERT(!result->IsFailure());
1671 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001672 return regexp;
1673}
1674
1675
lrn@chromium.org303ada72010-10-27 09:33:13 +00001676static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001677 HandleScope scope;
1678 ASSERT(args.length() == 1);
1679 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1680 // This is necessary to enable fast checks for absence of elements
1681 // on Array.prototype and below.
1682 prototype->set_elements(Heap::empty_fixed_array());
1683 return Smi::FromInt(0);
1684}
1685
1686
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001687static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1688 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001689 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001690 Handle<String> key = Factory::LookupAsciiSymbol(name);
1691 Handle<Code> code(Builtins::builtin(builtin_name));
1692 Handle<JSFunction> optimized = Factory::NewFunction(key,
1693 JS_OBJECT_TYPE,
1694 JSObject::kHeaderSize,
1695 code,
1696 false);
1697 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001698 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001699 return optimized;
1700}
1701
1702
lrn@chromium.org303ada72010-10-27 09:33:13 +00001703static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001704 HandleScope scope;
1705 ASSERT(args.length() == 1);
1706 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1707
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001708 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1709 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001710 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1711 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1712 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1713 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001714 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001715
1716 return *holder;
1717}
1718
1719
lrn@chromium.org303ada72010-10-27 09:33:13 +00001720static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001721 // Returns a real global receiver, not one of builtins object.
1722 Context* global_context = Top::context()->global()->global_context();
1723 return global_context->global()->global_receiver();
1724}
1725
1726
lrn@chromium.org303ada72010-10-27 09:33:13 +00001727static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001728 HandleScope scope;
1729 ASSERT(args.length() == 4);
1730 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1731 int index = Smi::cast(args[1])->value();
1732 Handle<String> pattern = args.at<String>(2);
1733 Handle<String> flags = args.at<String>(3);
1734
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001735 // Get the RegExp function from the context in the literals array.
1736 // This is the RegExp function from the context in which the
1737 // function was created. We do not use the RegExp function from the
1738 // current global context because this might be the RegExp function
1739 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001740 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001741 Handle<JSFunction>(
1742 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001743 // Compute the regular expression literal.
1744 bool has_pending_exception;
1745 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001746 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1747 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001748 if (has_pending_exception) {
1749 ASSERT(Top::has_pending_exception());
1750 return Failure::Exception();
1751 }
1752 literals->set(index, *regexp);
1753 return *regexp;
1754}
1755
1756
lrn@chromium.org303ada72010-10-27 09:33:13 +00001757static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001758 NoHandleAllocation ha;
1759 ASSERT(args.length() == 1);
1760
1761 CONVERT_CHECKED(JSFunction, f, args[0]);
1762 return f->shared()->name();
1763}
1764
1765
lrn@chromium.org303ada72010-10-27 09:33:13 +00001766static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001767 NoHandleAllocation ha;
1768 ASSERT(args.length() == 2);
1769
1770 CONVERT_CHECKED(JSFunction, f, args[0]);
1771 CONVERT_CHECKED(String, name, args[1]);
1772 f->shared()->set_name(name);
1773 return Heap::undefined_value();
1774}
1775
1776
lrn@chromium.org303ada72010-10-27 09:33:13 +00001777static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001778 NoHandleAllocation ha;
1779 ASSERT(args.length() == 1);
1780
1781 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001782 Object* obj;
1783 { MaybeObject* maybe_obj = f->RemovePrototype();
1784 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1785 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001786
1787 return Heap::undefined_value();
1788}
1789
1790
lrn@chromium.org303ada72010-10-27 09:33:13 +00001791static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001792 HandleScope scope;
1793 ASSERT(args.length() == 1);
1794
1795 CONVERT_CHECKED(JSFunction, fun, args[0]);
1796 Handle<Object> script = Handle<Object>(fun->shared()->script());
1797 if (!script->IsScript()) return Heap::undefined_value();
1798
1799 return *GetScriptWrapper(Handle<Script>::cast(script));
1800}
1801
1802
lrn@chromium.org303ada72010-10-27 09:33:13 +00001803static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804 NoHandleAllocation ha;
1805 ASSERT(args.length() == 1);
1806
1807 CONVERT_CHECKED(JSFunction, f, args[0]);
1808 return f->shared()->GetSourceCode();
1809}
1810
1811
lrn@chromium.org303ada72010-10-27 09:33:13 +00001812static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001813 NoHandleAllocation ha;
1814 ASSERT(args.length() == 1);
1815
1816 CONVERT_CHECKED(JSFunction, fun, args[0]);
1817 int pos = fun->shared()->start_position();
1818 return Smi::FromInt(pos);
1819}
1820
1821
lrn@chromium.org303ada72010-10-27 09:33:13 +00001822static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001823 ASSERT(args.length() == 2);
1824
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001825 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001826 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1827
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001828 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1829
1830 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001831 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001832}
1833
1834
1835
lrn@chromium.org303ada72010-10-27 09:33:13 +00001836static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001837 NoHandleAllocation ha;
1838 ASSERT(args.length() == 2);
1839
1840 CONVERT_CHECKED(JSFunction, fun, args[0]);
1841 CONVERT_CHECKED(String, name, args[1]);
1842 fun->SetInstanceClassName(name);
1843 return Heap::undefined_value();
1844}
1845
1846
lrn@chromium.org303ada72010-10-27 09:33:13 +00001847static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001848 NoHandleAllocation ha;
1849 ASSERT(args.length() == 2);
1850
1851 CONVERT_CHECKED(JSFunction, fun, args[0]);
1852 CONVERT_CHECKED(Smi, length, args[1]);
1853 fun->shared()->set_length(length->value());
1854 return length;
1855}
1856
1857
lrn@chromium.org303ada72010-10-27 09:33:13 +00001858static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001859 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001860 ASSERT(args.length() == 2);
1861
1862 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001863 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001864 Object* obj;
1865 { MaybeObject* maybe_obj =
1866 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1867 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1868 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 return args[0]; // return TOS
1870}
1871
1872
lrn@chromium.org303ada72010-10-27 09:33:13 +00001873static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001874 NoHandleAllocation ha;
1875 ASSERT(args.length() == 1);
1876
1877 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001878 return f->shared()->IsApiFunction() ? Heap::true_value()
1879 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001880}
1881
lrn@chromium.org303ada72010-10-27 09:33:13 +00001882static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001883 NoHandleAllocation ha;
1884 ASSERT(args.length() == 1);
1885
1886 CONVERT_CHECKED(JSFunction, f, args[0]);
1887 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1888}
1889
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001890
lrn@chromium.org303ada72010-10-27 09:33:13 +00001891static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001892 HandleScope scope;
1893 ASSERT(args.length() == 2);
1894
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001895 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 Handle<Object> code = args.at<Object>(1);
1897
1898 Handle<Context> context(target->context());
1899
1900 if (!code->IsNull()) {
1901 RUNTIME_ASSERT(code->IsJSFunction());
1902 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001903 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001904
1905 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001906 return Failure::Exception();
1907 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001908 // Since we don't store the source for this we should never
1909 // optimize this.
1910 shared->code()->set_optimizable(false);
1911
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001912 // Set the code, scope info, formal parameter count,
1913 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001914 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001915 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001916 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001917 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001919 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001920 // Set the source code of the target function to undefined.
1921 // SetCode is only used for built-in constructors like String,
1922 // Array, and Object, and some web code
1923 // doesn't like seeing source code for constructors.
1924 target->shared()->set_script(Heap::undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001925 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001926 // Clear the optimization hints related to the compiled code as these are no
1927 // longer valid when the code is overwritten.
1928 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 context = Handle<Context>(fun->context());
1930
1931 // Make sure we get a fresh copy of the literal vector to avoid
1932 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001933 int number_of_literals = fun->NumberOfLiterals();
1934 Handle<FixedArray> literals =
1935 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001936 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001937 // Insert the object, regexp and array functions in the literals
1938 // array prefix. These are the functions that will be used when
1939 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001940 literals->set(JSFunction::kLiteralGlobalContextIndex,
1941 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001942 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001943 // It's okay to skip the write barrier here because the literals
1944 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001945 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001946 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947 }
1948
1949 target->set_context(*context);
1950 return *target;
1951}
1952
1953
lrn@chromium.org303ada72010-10-27 09:33:13 +00001954static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001955 HandleScope scope;
1956 ASSERT(args.length() == 2);
1957 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1958 CONVERT_SMI_CHECKED(num, args[1]);
1959 RUNTIME_ASSERT(num >= 0);
1960 SetExpectedNofProperties(function, num);
1961 return Heap::undefined_value();
1962}
1963
1964
lrn@chromium.org303ada72010-10-27 09:33:13 +00001965MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001966 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001967 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001968 if (code <= 0xffff) {
1969 return Heap::LookupSingleCharacterStringFromCode(code);
1970 }
1971 }
1972 return Heap::empty_string();
1973}
1974
1975
lrn@chromium.org303ada72010-10-27 09:33:13 +00001976static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001977 NoHandleAllocation ha;
1978 ASSERT(args.length() == 2);
1979
1980 CONVERT_CHECKED(String, subject, args[0]);
1981 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001982 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001983
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001984 uint32_t i = 0;
1985 if (index->IsSmi()) {
1986 int value = Smi::cast(index)->value();
1987 if (value < 0) return Heap::nan_value();
1988 i = value;
1989 } else {
1990 ASSERT(index->IsHeapNumber());
1991 double value = HeapNumber::cast(index)->value();
1992 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001993 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001994
1995 // Flatten the string. If someone wants to get a char at an index
1996 // in a cons string, it is likely that more indices will be
1997 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001998 Object* flat;
1999 { MaybeObject* maybe_flat = subject->TryFlatten();
2000 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2001 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002002 subject = String::cast(flat);
2003
2004 if (i >= static_cast<uint32_t>(subject->length())) {
2005 return Heap::nan_value();
2006 }
2007
2008 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002009}
2010
2011
lrn@chromium.org303ada72010-10-27 09:33:13 +00002012static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 NoHandleAllocation ha;
2014 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002015 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002016}
2017
lrn@chromium.org25156de2010-04-06 13:10:27 +00002018
2019class FixedArrayBuilder {
2020 public:
2021 explicit FixedArrayBuilder(int initial_capacity)
2022 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
2023 length_(0) {
2024 // Require a non-zero initial size. Ensures that doubling the size to
2025 // extend the array will work.
2026 ASSERT(initial_capacity > 0);
2027 }
2028
2029 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2030 : array_(backing_store),
2031 length_(0) {
2032 // Require a non-zero initial size. Ensures that doubling the size to
2033 // extend the array will work.
2034 ASSERT(backing_store->length() > 0);
2035 }
2036
2037 bool HasCapacity(int elements) {
2038 int length = array_->length();
2039 int required_length = length_ + elements;
2040 return (length >= required_length);
2041 }
2042
2043 void EnsureCapacity(int elements) {
2044 int length = array_->length();
2045 int required_length = length_ + elements;
2046 if (length < required_length) {
2047 int new_length = length;
2048 do {
2049 new_length *= 2;
2050 } while (new_length < required_length);
2051 Handle<FixedArray> extended_array =
2052 Factory::NewFixedArrayWithHoles(new_length);
2053 array_->CopyTo(0, *extended_array, 0, length_);
2054 array_ = extended_array;
2055 }
2056 }
2057
2058 void Add(Object* value) {
2059 ASSERT(length_ < capacity());
2060 array_->set(length_, value);
2061 length_++;
2062 }
2063
2064 void Add(Smi* value) {
2065 ASSERT(length_ < capacity());
2066 array_->set(length_, value);
2067 length_++;
2068 }
2069
2070 Handle<FixedArray> array() {
2071 return array_;
2072 }
2073
2074 int length() {
2075 return length_;
2076 }
2077
2078 int capacity() {
2079 return array_->length();
2080 }
2081
2082 Handle<JSArray> ToJSArray() {
2083 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
2084 result_array->set_length(Smi::FromInt(length_));
2085 return result_array;
2086 }
2087
2088 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2089 target_array->set_elements(*array_);
2090 target_array->set_length(Smi::FromInt(length_));
2091 return target_array;
2092 }
2093
2094 private:
2095 Handle<FixedArray> array_;
2096 int length_;
2097};
2098
2099
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002100// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002101const int kStringBuilderConcatHelperLengthBits = 11;
2102const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002103
2104template <typename schar>
2105static inline void StringBuilderConcatHelper(String*,
2106 schar*,
2107 FixedArray*,
2108 int);
2109
lrn@chromium.org25156de2010-04-06 13:10:27 +00002110typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2111 StringBuilderSubstringLength;
2112typedef BitField<int,
2113 kStringBuilderConcatHelperLengthBits,
2114 kStringBuilderConcatHelperPositionBits>
2115 StringBuilderSubstringPosition;
2116
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002117
2118class ReplacementStringBuilder {
2119 public:
2120 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00002121 : array_builder_(estimated_part_count),
2122 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002123 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002124 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002125 // Require a non-zero initial size. Ensures that doubling the size to
2126 // extend the array will work.
2127 ASSERT(estimated_part_count > 0);
2128 }
2129
lrn@chromium.org25156de2010-04-06 13:10:27 +00002130 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2131 int from,
2132 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002133 ASSERT(from >= 0);
2134 int length = to - from;
2135 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002136 if (StringBuilderSubstringLength::is_valid(length) &&
2137 StringBuilderSubstringPosition::is_valid(from)) {
2138 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2139 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002140 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002141 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002142 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002143 builder->Add(Smi::FromInt(-length));
2144 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002145 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002146 }
2147
2148
2149 void EnsureCapacity(int elements) {
2150 array_builder_.EnsureCapacity(elements);
2151 }
2152
2153
2154 void AddSubjectSlice(int from, int to) {
2155 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002156 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002157 }
2158
2159
2160 void AddString(Handle<String> string) {
2161 int length = string->length();
2162 ASSERT(length > 0);
2163 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002164 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002165 is_ascii_ = false;
2166 }
2167 IncrementCharacterCount(length);
2168 }
2169
2170
2171 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002172 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002173 return Factory::empty_string();
2174 }
2175
2176 Handle<String> joined_string;
2177 if (is_ascii_) {
2178 joined_string = NewRawAsciiString(character_count_);
2179 AssertNoAllocation no_alloc;
2180 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2181 char* char_buffer = seq->GetChars();
2182 StringBuilderConcatHelper(*subject_,
2183 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002184 *array_builder_.array(),
2185 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002186 } else {
2187 // Non-ASCII.
2188 joined_string = NewRawTwoByteString(character_count_);
2189 AssertNoAllocation no_alloc;
2190 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2191 uc16* char_buffer = seq->GetChars();
2192 StringBuilderConcatHelper(*subject_,
2193 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002194 *array_builder_.array(),
2195 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002196 }
2197 return joined_string;
2198 }
2199
2200
2201 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002202 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002203 V8::FatalProcessOutOfMemory("String.replace result too large.");
2204 }
2205 character_count_ += by;
2206 }
2207
lrn@chromium.org25156de2010-04-06 13:10:27 +00002208 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002209 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002210 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002211
lrn@chromium.org25156de2010-04-06 13:10:27 +00002212 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002213 Handle<String> NewRawAsciiString(int size) {
2214 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2215 }
2216
2217
2218 Handle<String> NewRawTwoByteString(int size) {
2219 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2220 }
2221
2222
2223 void AddElement(Object* element) {
2224 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002225 ASSERT(array_builder_.capacity() > array_builder_.length());
2226 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002227 }
2228
lrn@chromium.org25156de2010-04-06 13:10:27 +00002229 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002230 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002231 int character_count_;
2232 bool is_ascii_;
2233};
2234
2235
2236class CompiledReplacement {
2237 public:
2238 CompiledReplacement()
2239 : parts_(1), replacement_substrings_(0) {}
2240
2241 void Compile(Handle<String> replacement,
2242 int capture_count,
2243 int subject_length);
2244
2245 void Apply(ReplacementStringBuilder* builder,
2246 int match_from,
2247 int match_to,
2248 Handle<JSArray> last_match_info);
2249
2250 // Number of distinct parts of the replacement pattern.
2251 int parts() {
2252 return parts_.length();
2253 }
2254 private:
2255 enum PartType {
2256 SUBJECT_PREFIX = 1,
2257 SUBJECT_SUFFIX,
2258 SUBJECT_CAPTURE,
2259 REPLACEMENT_SUBSTRING,
2260 REPLACEMENT_STRING,
2261
2262 NUMBER_OF_PART_TYPES
2263 };
2264
2265 struct ReplacementPart {
2266 static inline ReplacementPart SubjectMatch() {
2267 return ReplacementPart(SUBJECT_CAPTURE, 0);
2268 }
2269 static inline ReplacementPart SubjectCapture(int capture_index) {
2270 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2271 }
2272 static inline ReplacementPart SubjectPrefix() {
2273 return ReplacementPart(SUBJECT_PREFIX, 0);
2274 }
2275 static inline ReplacementPart SubjectSuffix(int subject_length) {
2276 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2277 }
2278 static inline ReplacementPart ReplacementString() {
2279 return ReplacementPart(REPLACEMENT_STRING, 0);
2280 }
2281 static inline ReplacementPart ReplacementSubString(int from, int to) {
2282 ASSERT(from >= 0);
2283 ASSERT(to > from);
2284 return ReplacementPart(-from, to);
2285 }
2286
2287 // If tag <= 0 then it is the negation of a start index of a substring of
2288 // the replacement pattern, otherwise it's a value from PartType.
2289 ReplacementPart(int tag, int data)
2290 : tag(tag), data(data) {
2291 // Must be non-positive or a PartType value.
2292 ASSERT(tag < NUMBER_OF_PART_TYPES);
2293 }
2294 // Either a value of PartType or a non-positive number that is
2295 // the negation of an index into the replacement string.
2296 int tag;
2297 // The data value's interpretation depends on the value of tag:
2298 // tag == SUBJECT_PREFIX ||
2299 // tag == SUBJECT_SUFFIX: data is unused.
2300 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2301 // tag == REPLACEMENT_SUBSTRING ||
2302 // tag == REPLACEMENT_STRING: data is index into array of substrings
2303 // of the replacement string.
2304 // tag <= 0: Temporary representation of the substring of the replacement
2305 // string ranging over -tag .. data.
2306 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2307 // substring objects.
2308 int data;
2309 };
2310
2311 template<typename Char>
2312 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2313 Vector<Char> characters,
2314 int capture_count,
2315 int subject_length) {
2316 int length = characters.length();
2317 int last = 0;
2318 for (int i = 0; i < length; i++) {
2319 Char c = characters[i];
2320 if (c == '$') {
2321 int next_index = i + 1;
2322 if (next_index == length) { // No next character!
2323 break;
2324 }
2325 Char c2 = characters[next_index];
2326 switch (c2) {
2327 case '$':
2328 if (i > last) {
2329 // There is a substring before. Include the first "$".
2330 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2331 last = next_index + 1; // Continue after the second "$".
2332 } else {
2333 // Let the next substring start with the second "$".
2334 last = next_index;
2335 }
2336 i = next_index;
2337 break;
2338 case '`':
2339 if (i > last) {
2340 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2341 }
2342 parts->Add(ReplacementPart::SubjectPrefix());
2343 i = next_index;
2344 last = i + 1;
2345 break;
2346 case '\'':
2347 if (i > last) {
2348 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2349 }
2350 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2351 i = next_index;
2352 last = i + 1;
2353 break;
2354 case '&':
2355 if (i > last) {
2356 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2357 }
2358 parts->Add(ReplacementPart::SubjectMatch());
2359 i = next_index;
2360 last = i + 1;
2361 break;
2362 case '0':
2363 case '1':
2364 case '2':
2365 case '3':
2366 case '4':
2367 case '5':
2368 case '6':
2369 case '7':
2370 case '8':
2371 case '9': {
2372 int capture_ref = c2 - '0';
2373 if (capture_ref > capture_count) {
2374 i = next_index;
2375 continue;
2376 }
2377 int second_digit_index = next_index + 1;
2378 if (second_digit_index < length) {
2379 // Peek ahead to see if we have two digits.
2380 Char c3 = characters[second_digit_index];
2381 if ('0' <= c3 && c3 <= '9') { // Double digits.
2382 int double_digit_ref = capture_ref * 10 + c3 - '0';
2383 if (double_digit_ref <= capture_count) {
2384 next_index = second_digit_index;
2385 capture_ref = double_digit_ref;
2386 }
2387 }
2388 }
2389 if (capture_ref > 0) {
2390 if (i > last) {
2391 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2392 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002393 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002394 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2395 last = next_index + 1;
2396 }
2397 i = next_index;
2398 break;
2399 }
2400 default:
2401 i = next_index;
2402 break;
2403 }
2404 }
2405 }
2406 if (length > last) {
2407 if (last == 0) {
2408 parts->Add(ReplacementPart::ReplacementString());
2409 } else {
2410 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2411 }
2412 }
2413 }
2414
2415 ZoneList<ReplacementPart> parts_;
2416 ZoneList<Handle<String> > replacement_substrings_;
2417};
2418
2419
2420void CompiledReplacement::Compile(Handle<String> replacement,
2421 int capture_count,
2422 int subject_length) {
2423 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002424 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002425 AssertNoAllocation no_alloc;
2426 ParseReplacementPattern(&parts_,
2427 replacement->ToAsciiVector(),
2428 capture_count,
2429 subject_length);
2430 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002431 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002432 AssertNoAllocation no_alloc;
2433
2434 ParseReplacementPattern(&parts_,
2435 replacement->ToUC16Vector(),
2436 capture_count,
2437 subject_length);
2438 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002439 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002440 int substring_index = 0;
2441 for (int i = 0, n = parts_.length(); i < n; i++) {
2442 int tag = parts_[i].tag;
2443 if (tag <= 0) { // A replacement string slice.
2444 int from = -tag;
2445 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002446 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002447 parts_[i].tag = REPLACEMENT_SUBSTRING;
2448 parts_[i].data = substring_index;
2449 substring_index++;
2450 } else if (tag == REPLACEMENT_STRING) {
2451 replacement_substrings_.Add(replacement);
2452 parts_[i].data = substring_index;
2453 substring_index++;
2454 }
2455 }
2456}
2457
2458
2459void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2460 int match_from,
2461 int match_to,
2462 Handle<JSArray> last_match_info) {
2463 for (int i = 0, n = parts_.length(); i < n; i++) {
2464 ReplacementPart part = parts_[i];
2465 switch (part.tag) {
2466 case SUBJECT_PREFIX:
2467 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2468 break;
2469 case SUBJECT_SUFFIX: {
2470 int subject_length = part.data;
2471 if (match_to < subject_length) {
2472 builder->AddSubjectSlice(match_to, subject_length);
2473 }
2474 break;
2475 }
2476 case SUBJECT_CAPTURE: {
2477 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002478 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002479 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2480 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2481 if (from >= 0 && to > from) {
2482 builder->AddSubjectSlice(from, to);
2483 }
2484 break;
2485 }
2486 case REPLACEMENT_SUBSTRING:
2487 case REPLACEMENT_STRING:
2488 builder->AddString(replacement_substrings_[part.data]);
2489 break;
2490 default:
2491 UNREACHABLE();
2492 }
2493 }
2494}
2495
2496
2497
lrn@chromium.org303ada72010-10-27 09:33:13 +00002498MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2499 String* subject,
2500 JSRegExp* regexp,
2501 String* replacement,
2502 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002503 ASSERT(subject->IsFlat());
2504 ASSERT(replacement->IsFlat());
2505
2506 HandleScope handles;
2507
2508 int length = subject->length();
2509 Handle<String> subject_handle(subject);
2510 Handle<JSRegExp> regexp_handle(regexp);
2511 Handle<String> replacement_handle(replacement);
2512 Handle<JSArray> last_match_info_handle(last_match_info);
2513 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2514 subject_handle,
2515 0,
2516 last_match_info_handle);
2517 if (match.is_null()) {
2518 return Failure::Exception();
2519 }
2520 if (match->IsNull()) {
2521 return *subject_handle;
2522 }
2523
2524 int capture_count = regexp_handle->CaptureCount();
2525
2526 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002527 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002528 CompiledReplacement compiled_replacement;
2529 compiled_replacement.Compile(replacement_handle,
2530 capture_count,
2531 length);
2532
2533 bool is_global = regexp_handle->GetFlags().is_global();
2534
2535 // Guessing the number of parts that the final result string is built
2536 // from. Global regexps can match any number of times, so we guess
2537 // conservatively.
2538 int expected_parts =
2539 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2540 ReplacementStringBuilder builder(subject_handle, expected_parts);
2541
2542 // Index of end of last match.
2543 int prev = 0;
2544
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002545 // Number of parts added by compiled replacement plus preceeding
2546 // string and possibly suffix after last match. It is possible for
2547 // all components to use two elements when encoded as two smis.
2548 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002549 bool matched = true;
2550 do {
2551 ASSERT(last_match_info_handle->HasFastElements());
2552 // Increase the capacity of the builder before entering local handle-scope,
2553 // so its internal buffer can safely allocate a new handle if it grows.
2554 builder.EnsureCapacity(parts_added_per_loop);
2555
2556 HandleScope loop_scope;
2557 int start, end;
2558 {
2559 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002560 FixedArray* match_info_array =
2561 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002562
2563 ASSERT_EQ(capture_count * 2 + 2,
2564 RegExpImpl::GetLastCaptureCount(match_info_array));
2565 start = RegExpImpl::GetCapture(match_info_array, 0);
2566 end = RegExpImpl::GetCapture(match_info_array, 1);
2567 }
2568
2569 if (prev < start) {
2570 builder.AddSubjectSlice(prev, start);
2571 }
2572 compiled_replacement.Apply(&builder,
2573 start,
2574 end,
2575 last_match_info_handle);
2576 prev = end;
2577
2578 // Only continue checking for global regexps.
2579 if (!is_global) break;
2580
2581 // Continue from where the match ended, unless it was an empty match.
2582 int next = end;
2583 if (start == end) {
2584 next = end + 1;
2585 if (next > length) break;
2586 }
2587
2588 match = RegExpImpl::Exec(regexp_handle,
2589 subject_handle,
2590 next,
2591 last_match_info_handle);
2592 if (match.is_null()) {
2593 return Failure::Exception();
2594 }
2595 matched = !match->IsNull();
2596 } while (matched);
2597
2598 if (prev < length) {
2599 builder.AddSubjectSlice(prev, length);
2600 }
2601
2602 return *(builder.ToString());
2603}
2604
2605
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002606template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002607MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2608 String* subject,
2609 JSRegExp* regexp,
2610 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002611 ASSERT(subject->IsFlat());
2612
2613 HandleScope handles;
2614
2615 Handle<String> subject_handle(subject);
2616 Handle<JSRegExp> regexp_handle(regexp);
2617 Handle<JSArray> last_match_info_handle(last_match_info);
2618 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2619 subject_handle,
2620 0,
2621 last_match_info_handle);
2622 if (match.is_null()) return Failure::Exception();
2623 if (match->IsNull()) return *subject_handle;
2624
2625 ASSERT(last_match_info_handle->HasFastElements());
2626
2627 HandleScope loop_scope;
2628 int start, end;
2629 {
2630 AssertNoAllocation match_info_array_is_not_in_a_handle;
2631 FixedArray* match_info_array =
2632 FixedArray::cast(last_match_info_handle->elements());
2633
2634 start = RegExpImpl::GetCapture(match_info_array, 0);
2635 end = RegExpImpl::GetCapture(match_info_array, 1);
2636 }
2637
2638 int length = subject->length();
2639 int new_length = length - (end - start);
2640 if (new_length == 0) {
2641 return Heap::empty_string();
2642 }
2643 Handle<ResultSeqString> answer;
2644 if (ResultSeqString::kHasAsciiEncoding) {
2645 answer =
2646 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2647 } else {
2648 answer =
2649 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2650 }
2651
2652 // If the regexp isn't global, only match once.
2653 if (!regexp_handle->GetFlags().is_global()) {
2654 if (start > 0) {
2655 String::WriteToFlat(*subject_handle,
2656 answer->GetChars(),
2657 0,
2658 start);
2659 }
2660 if (end < length) {
2661 String::WriteToFlat(*subject_handle,
2662 answer->GetChars() + start,
2663 end,
2664 length);
2665 }
2666 return *answer;
2667 }
2668
2669 int prev = 0; // Index of end of last match.
2670 int next = 0; // Start of next search (prev unless last match was empty).
2671 int position = 0;
2672
2673 do {
2674 if (prev < start) {
2675 // Add substring subject[prev;start] to answer string.
2676 String::WriteToFlat(*subject_handle,
2677 answer->GetChars() + position,
2678 prev,
2679 start);
2680 position += start - prev;
2681 }
2682 prev = end;
2683 next = end;
2684 // Continue from where the match ended, unless it was an empty match.
2685 if (start == end) {
2686 next++;
2687 if (next > length) break;
2688 }
2689 match = RegExpImpl::Exec(regexp_handle,
2690 subject_handle,
2691 next,
2692 last_match_info_handle);
2693 if (match.is_null()) return Failure::Exception();
2694 if (match->IsNull()) break;
2695
2696 ASSERT(last_match_info_handle->HasFastElements());
2697 HandleScope loop_scope;
2698 {
2699 AssertNoAllocation match_info_array_is_not_in_a_handle;
2700 FixedArray* match_info_array =
2701 FixedArray::cast(last_match_info_handle->elements());
2702 start = RegExpImpl::GetCapture(match_info_array, 0);
2703 end = RegExpImpl::GetCapture(match_info_array, 1);
2704 }
2705 } while (true);
2706
2707 if (prev < length) {
2708 // Add substring subject[prev;length] to answer string.
2709 String::WriteToFlat(*subject_handle,
2710 answer->GetChars() + position,
2711 prev,
2712 length);
2713 position += length - prev;
2714 }
2715
2716 if (position == 0) {
2717 return Heap::empty_string();
2718 }
2719
2720 // Shorten string and fill
2721 int string_size = ResultSeqString::SizeFor(position);
2722 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2723 int delta = allocated_string_size - string_size;
2724
2725 answer->set_length(position);
2726 if (delta == 0) return *answer;
2727
2728 Address end_of_string = answer->address() + string_size;
2729 Heap::CreateFillerObjectAt(end_of_string, delta);
2730
2731 return *answer;
2732}
2733
2734
lrn@chromium.org303ada72010-10-27 09:33:13 +00002735static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002736 ASSERT(args.length() == 4);
2737
2738 CONVERT_CHECKED(String, subject, args[0]);
2739 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002740 Object* flat_subject;
2741 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2742 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2743 return maybe_flat_subject;
2744 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002745 }
2746 subject = String::cast(flat_subject);
2747 }
2748
2749 CONVERT_CHECKED(String, replacement, args[2]);
2750 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002751 Object* flat_replacement;
2752 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2753 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2754 return maybe_flat_replacement;
2755 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002756 }
2757 replacement = String::cast(flat_replacement);
2758 }
2759
2760 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2761 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2762
2763 ASSERT(last_match_info->HasFastElements());
2764
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002765 if (replacement->length() == 0) {
2766 if (subject->HasOnlyAsciiChars()) {
2767 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2768 subject, regexp, last_match_info);
2769 } else {
2770 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2771 subject, regexp, last_match_info);
2772 }
2773 }
2774
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002775 return StringReplaceRegExpWithString(subject,
2776 regexp,
2777 replacement,
2778 last_match_info);
2779}
2780
2781
ager@chromium.org7c537e22008-10-16 08:43:32 +00002782// Perform string match of pattern on subject, starting at start index.
2783// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002784// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002785int Runtime::StringMatch(Handle<String> sub,
2786 Handle<String> pat,
2787 int start_index) {
2788 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002789 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002790
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002791 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002792 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002793
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002794 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002795 if (start_index + pattern_length > subject_length) return -1;
2796
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002797 if (!sub->IsFlat()) FlattenString(sub);
2798 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002799
ager@chromium.org7c537e22008-10-16 08:43:32 +00002800 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002801 // Extract flattened substrings of cons strings before determining asciiness.
2802 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002803 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002804 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002805 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002806
ager@chromium.org7c537e22008-10-16 08:43:32 +00002807 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002808 if (seq_pat->IsAsciiRepresentation()) {
2809 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2810 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002811 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002812 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002813 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002814 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002815 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2816 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002817 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002818 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002819 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002820}
2821
2822
lrn@chromium.org303ada72010-10-27 09:33:13 +00002823static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002824 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002825 ASSERT(args.length() == 3);
2826
ager@chromium.org7c537e22008-10-16 08:43:32 +00002827 CONVERT_ARG_CHECKED(String, sub, 0);
2828 CONVERT_ARG_CHECKED(String, pat, 1);
2829
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002830 Object* index = args[2];
2831 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002832 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002833
ager@chromium.org870a0b62008-11-04 11:43:05 +00002834 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002835 int position = Runtime::StringMatch(sub, pat, start_index);
2836 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002837}
2838
2839
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002840template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002841static int StringMatchBackwards(Vector<const schar> subject,
2842 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002843 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002844 int pattern_length = pattern.length();
2845 ASSERT(pattern_length >= 1);
2846 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002847
2848 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002849 for (int i = 0; i < pattern_length; i++) {
2850 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002851 if (c > String::kMaxAsciiCharCode) {
2852 return -1;
2853 }
2854 }
2855 }
2856
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002857 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002858 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002859 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002860 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002861 while (j < pattern_length) {
2862 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002863 break;
2864 }
2865 j++;
2866 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002867 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002868 return i;
2869 }
2870 }
2871 return -1;
2872}
2873
lrn@chromium.org303ada72010-10-27 09:33:13 +00002874static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002875 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002876 ASSERT(args.length() == 3);
2877
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002878 CONVERT_ARG_CHECKED(String, sub, 0);
2879 CONVERT_ARG_CHECKED(String, pat, 1);
2880
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002881 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002882 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002883 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002884
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002885 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002886 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002887
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002888 if (start_index + pat_length > sub_length) {
2889 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002890 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002891
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002892 if (pat_length == 0) {
2893 return Smi::FromInt(start_index);
2894 }
2895
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002896 if (!sub->IsFlat()) FlattenString(sub);
2897 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002898
2899 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2900
2901 int position = -1;
2902
2903 if (pat->IsAsciiRepresentation()) {
2904 Vector<const char> pat_vector = pat->ToAsciiVector();
2905 if (sub->IsAsciiRepresentation()) {
2906 position = StringMatchBackwards(sub->ToAsciiVector(),
2907 pat_vector,
2908 start_index);
2909 } else {
2910 position = StringMatchBackwards(sub->ToUC16Vector(),
2911 pat_vector,
2912 start_index);
2913 }
2914 } else {
2915 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2916 if (sub->IsAsciiRepresentation()) {
2917 position = StringMatchBackwards(sub->ToAsciiVector(),
2918 pat_vector,
2919 start_index);
2920 } else {
2921 position = StringMatchBackwards(sub->ToUC16Vector(),
2922 pat_vector,
2923 start_index);
2924 }
2925 }
2926
2927 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002928}
2929
2930
lrn@chromium.org303ada72010-10-27 09:33:13 +00002931static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002932 NoHandleAllocation ha;
2933 ASSERT(args.length() == 2);
2934
2935 CONVERT_CHECKED(String, str1, args[0]);
2936 CONVERT_CHECKED(String, str2, args[1]);
2937
2938 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002939 int str1_length = str1->length();
2940 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002941
2942 // Decide trivial cases without flattening.
2943 if (str1_length == 0) {
2944 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2945 return Smi::FromInt(-str2_length);
2946 } else {
2947 if (str2_length == 0) return Smi::FromInt(str1_length);
2948 }
2949
2950 int end = str1_length < str2_length ? str1_length : str2_length;
2951
2952 // No need to flatten if we are going to find the answer on the first
2953 // character. At this point we know there is at least one character
2954 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002955 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002956 if (d != 0) return Smi::FromInt(d);
2957
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002958 str1->TryFlatten();
2959 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002960
2961 static StringInputBuffer buf1;
2962 static StringInputBuffer buf2;
2963
2964 buf1.Reset(str1);
2965 buf2.Reset(str2);
2966
2967 for (int i = 0; i < end; i++) {
2968 uint16_t char1 = buf1.GetNext();
2969 uint16_t char2 = buf2.GetNext();
2970 if (char1 != char2) return Smi::FromInt(char1 - char2);
2971 }
2972
2973 return Smi::FromInt(str1_length - str2_length);
2974}
2975
2976
lrn@chromium.org303ada72010-10-27 09:33:13 +00002977static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002978 NoHandleAllocation ha;
2979 ASSERT(args.length() == 3);
2980
2981 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002982 Object* from = args[1];
2983 Object* to = args[2];
2984 int start, end;
2985 // We have a fast integer-only case here to avoid a conversion to double in
2986 // the common case where from and to are Smis.
2987 if (from->IsSmi() && to->IsSmi()) {
2988 start = Smi::cast(from)->value();
2989 end = Smi::cast(to)->value();
2990 } else {
2991 CONVERT_DOUBLE_CHECKED(from_number, from);
2992 CONVERT_DOUBLE_CHECKED(to_number, to);
2993 start = FastD2I(from_number);
2994 end = FastD2I(to_number);
2995 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002996 RUNTIME_ASSERT(end >= start);
2997 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002998 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002999 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003000 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003001}
3002
3003
lrn@chromium.org303ada72010-10-27 09:33:13 +00003004static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003005 ASSERT_EQ(3, args.length());
3006
3007 CONVERT_ARG_CHECKED(String, subject, 0);
3008 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3009 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3010 HandleScope handles;
3011
3012 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3013
3014 if (match.is_null()) {
3015 return Failure::Exception();
3016 }
3017 if (match->IsNull()) {
3018 return Heap::null_value();
3019 }
3020 int length = subject->length();
3021
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003022 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003023 ZoneList<int> offsets(8);
3024 do {
3025 int start;
3026 int end;
3027 {
3028 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003029 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003030 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3031 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3032 }
3033 offsets.Add(start);
3034 offsets.Add(end);
3035 int index = start < end ? end : end + 1;
3036 if (index > length) break;
3037 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3038 if (match.is_null()) {
3039 return Failure::Exception();
3040 }
3041 } while (!match->IsNull());
3042 int matches = offsets.length() / 2;
3043 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
3044 for (int i = 0; i < matches ; i++) {
3045 int from = offsets.at(i * 2);
3046 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003047 Handle<String> match = Factory::NewSubString(subject, from, to);
3048 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003049 }
3050 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
3051 result->set_length(Smi::FromInt(matches));
3052 return *result;
3053}
3054
3055
lrn@chromium.org25156de2010-04-06 13:10:27 +00003056// Two smis before and after the match, for very long strings.
3057const int kMaxBuilderEntriesPerRegExpMatch = 5;
3058
3059
3060static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3061 Handle<JSArray> last_match_info,
3062 int match_start,
3063 int match_end) {
3064 // Fill last_match_info with a single capture.
3065 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3066 AssertNoAllocation no_gc;
3067 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3068 RegExpImpl::SetLastCaptureCount(elements, 2);
3069 RegExpImpl::SetLastInput(elements, *subject);
3070 RegExpImpl::SetLastSubject(elements, *subject);
3071 RegExpImpl::SetCapture(elements, 0, match_start);
3072 RegExpImpl::SetCapture(elements, 1, match_end);
3073}
3074
3075
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003076template <typename SubjectChar, typename PatternChar>
3077static bool SearchStringMultiple(Vector<const SubjectChar> subject,
3078 Vector<const PatternChar> pattern,
3079 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003080 FixedArrayBuilder* builder,
3081 int* match_pos) {
3082 int pos = *match_pos;
3083 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003084 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003085 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003086 StringSearch<PatternChar, SubjectChar> search(pattern);
3087 while (pos <= max_search_start) {
3088 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3089 *match_pos = pos;
3090 return false;
3091 }
3092 // Position of end of previous match.
3093 int match_end = pos + pattern_length;
3094 int new_pos = search.Search(subject, match_end);
3095 if (new_pos >= 0) {
3096 // A match.
3097 if (new_pos > match_end) {
3098 ReplacementStringBuilder::AddSubjectSlice(builder,
3099 match_end,
3100 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003101 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003102 pos = new_pos;
3103 builder->Add(pattern_string);
3104 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003105 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003106 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003107 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003108
lrn@chromium.org25156de2010-04-06 13:10:27 +00003109 if (pos < max_search_start) {
3110 ReplacementStringBuilder::AddSubjectSlice(builder,
3111 pos + pattern_length,
3112 subject_length);
3113 }
3114 *match_pos = pos;
3115 return true;
3116}
3117
3118
3119static bool SearchStringMultiple(Handle<String> subject,
3120 Handle<String> pattern,
3121 Handle<JSArray> last_match_info,
3122 FixedArrayBuilder* builder) {
3123 ASSERT(subject->IsFlat());
3124 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003125
3126 // Treating as if a previous match was before first character.
3127 int match_pos = -pattern->length();
3128
3129 for (;;) { // Break when search complete.
3130 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3131 AssertNoAllocation no_gc;
3132 if (subject->IsAsciiRepresentation()) {
3133 Vector<const char> subject_vector = subject->ToAsciiVector();
3134 if (pattern->IsAsciiRepresentation()) {
3135 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003136 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003137 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003138 builder,
3139 &match_pos)) break;
3140 } else {
3141 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003142 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003143 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003144 builder,
3145 &match_pos)) break;
3146 }
3147 } else {
3148 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3149 if (pattern->IsAsciiRepresentation()) {
3150 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003151 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003152 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003153 builder,
3154 &match_pos)) break;
3155 } else {
3156 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003157 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003158 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003159 builder,
3160 &match_pos)) break;
3161 }
3162 }
3163 }
3164
3165 if (match_pos >= 0) {
3166 SetLastMatchInfoNoCaptures(subject,
3167 last_match_info,
3168 match_pos,
3169 match_pos + pattern->length());
3170 return true;
3171 }
3172 return false; // No matches at all.
3173}
3174
3175
3176static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3177 Handle<String> subject,
3178 Handle<JSRegExp> regexp,
3179 Handle<JSArray> last_match_array,
3180 FixedArrayBuilder* builder) {
3181 ASSERT(subject->IsFlat());
3182 int match_start = -1;
3183 int match_end = 0;
3184 int pos = 0;
3185 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3186 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3187
3188 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003189 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003190 int subject_length = subject->length();
3191
3192 for (;;) { // Break on failure, return on exception.
3193 RegExpImpl::IrregexpResult result =
3194 RegExpImpl::IrregexpExecOnce(regexp,
3195 subject,
3196 pos,
3197 register_vector);
3198 if (result == RegExpImpl::RE_SUCCESS) {
3199 match_start = register_vector[0];
3200 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3201 if (match_end < match_start) {
3202 ReplacementStringBuilder::AddSubjectSlice(builder,
3203 match_end,
3204 match_start);
3205 }
3206 match_end = register_vector[1];
3207 HandleScope loop_scope;
3208 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3209 if (match_start != match_end) {
3210 pos = match_end;
3211 } else {
3212 pos = match_end + 1;
3213 if (pos > subject_length) break;
3214 }
3215 } else if (result == RegExpImpl::RE_FAILURE) {
3216 break;
3217 } else {
3218 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3219 return result;
3220 }
3221 }
3222
3223 if (match_start >= 0) {
3224 if (match_end < subject_length) {
3225 ReplacementStringBuilder::AddSubjectSlice(builder,
3226 match_end,
3227 subject_length);
3228 }
3229 SetLastMatchInfoNoCaptures(subject,
3230 last_match_array,
3231 match_start,
3232 match_end);
3233 return RegExpImpl::RE_SUCCESS;
3234 } else {
3235 return RegExpImpl::RE_FAILURE; // No matches at all.
3236 }
3237}
3238
3239
3240static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3241 Handle<String> subject,
3242 Handle<JSRegExp> regexp,
3243 Handle<JSArray> last_match_array,
3244 FixedArrayBuilder* builder) {
3245
3246 ASSERT(subject->IsFlat());
3247 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3248 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3249
3250 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003251 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003252
3253 RegExpImpl::IrregexpResult result =
3254 RegExpImpl::IrregexpExecOnce(regexp,
3255 subject,
3256 0,
3257 register_vector);
3258
3259 int capture_count = regexp->CaptureCount();
3260 int subject_length = subject->length();
3261
3262 // Position to search from.
3263 int pos = 0;
3264 // End of previous match. Differs from pos if match was empty.
3265 int match_end = 0;
3266 if (result == RegExpImpl::RE_SUCCESS) {
3267 // Need to keep a copy of the previous match for creating last_match_info
3268 // at the end, so we have two vectors that we swap between.
3269 OffsetsVector registers2(required_registers);
3270 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3271
3272 do {
3273 int match_start = register_vector[0];
3274 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3275 if (match_end < match_start) {
3276 ReplacementStringBuilder::AddSubjectSlice(builder,
3277 match_end,
3278 match_start);
3279 }
3280 match_end = register_vector[1];
3281
3282 {
3283 // Avoid accumulating new handles inside loop.
3284 HandleScope temp_scope;
3285 // Arguments array to replace function is match, captures, index and
3286 // subject, i.e., 3 + capture count in total.
3287 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003288 Handle<String> match = Factory::NewSubString(subject,
3289 match_start,
3290 match_end);
3291 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003292 for (int i = 1; i <= capture_count; i++) {
3293 int start = register_vector[i * 2];
3294 if (start >= 0) {
3295 int end = register_vector[i * 2 + 1];
3296 ASSERT(start <= end);
3297 Handle<String> substring = Factory::NewSubString(subject,
3298 start,
3299 end);
3300 elements->set(i, *substring);
3301 } else {
3302 ASSERT(register_vector[i * 2 + 1] < 0);
3303 elements->set(i, Heap::undefined_value());
3304 }
3305 }
3306 elements->set(capture_count + 1, Smi::FromInt(match_start));
3307 elements->set(capture_count + 2, *subject);
3308 builder->Add(*Factory::NewJSArrayWithElements(elements));
3309 }
3310 // Swap register vectors, so the last successful match is in
3311 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003312 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003313 prev_register_vector = register_vector;
3314 register_vector = tmp;
3315
3316 if (match_end > match_start) {
3317 pos = match_end;
3318 } else {
3319 pos = match_end + 1;
3320 if (pos > subject_length) {
3321 break;
3322 }
3323 }
3324
3325 result = RegExpImpl::IrregexpExecOnce(regexp,
3326 subject,
3327 pos,
3328 register_vector);
3329 } while (result == RegExpImpl::RE_SUCCESS);
3330
3331 if (result != RegExpImpl::RE_EXCEPTION) {
3332 // Finished matching, with at least one match.
3333 if (match_end < subject_length) {
3334 ReplacementStringBuilder::AddSubjectSlice(builder,
3335 match_end,
3336 subject_length);
3337 }
3338
3339 int last_match_capture_count = (capture_count + 1) * 2;
3340 int last_match_array_size =
3341 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3342 last_match_array->EnsureSize(last_match_array_size);
3343 AssertNoAllocation no_gc;
3344 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3345 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3346 RegExpImpl::SetLastSubject(elements, *subject);
3347 RegExpImpl::SetLastInput(elements, *subject);
3348 for (int i = 0; i < last_match_capture_count; i++) {
3349 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3350 }
3351 return RegExpImpl::RE_SUCCESS;
3352 }
3353 }
3354 // No matches at all, return failure or exception result directly.
3355 return result;
3356}
3357
3358
lrn@chromium.org303ada72010-10-27 09:33:13 +00003359static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003360 ASSERT(args.length() == 4);
3361 HandleScope handles;
3362
3363 CONVERT_ARG_CHECKED(String, subject, 1);
3364 if (!subject->IsFlat()) { FlattenString(subject); }
3365 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3366 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3367 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3368
3369 ASSERT(last_match_info->HasFastElements());
3370 ASSERT(regexp->GetFlags().is_global());
3371 Handle<FixedArray> result_elements;
3372 if (result_array->HasFastElements()) {
3373 result_elements =
3374 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3375 } else {
3376 result_elements = Factory::NewFixedArrayWithHoles(16);
3377 }
3378 FixedArrayBuilder builder(result_elements);
3379
3380 if (regexp->TypeTag() == JSRegExp::ATOM) {
3381 Handle<String> pattern(
3382 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003383 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003384 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3385 return *builder.ToJSArray(result_array);
3386 }
3387 return Heap::null_value();
3388 }
3389
3390 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3391
3392 RegExpImpl::IrregexpResult result;
3393 if (regexp->CaptureCount() == 0) {
3394 result = SearchRegExpNoCaptureMultiple(subject,
3395 regexp,
3396 last_match_info,
3397 &builder);
3398 } else {
3399 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3400 }
3401 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3402 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3403 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3404 return Failure::Exception();
3405}
3406
3407
lrn@chromium.org303ada72010-10-27 09:33:13 +00003408static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409 NoHandleAllocation ha;
3410 ASSERT(args.length() == 2);
3411
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003412 // Fast case where the result is a one character string.
3413 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3414 int value = Smi::cast(args[0])->value();
3415 int radix = Smi::cast(args[1])->value();
3416 if (value >= 0 && value < radix) {
3417 RUNTIME_ASSERT(radix <= 36);
3418 // Character array used for conversion.
3419 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3420 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3421 }
3422 }
3423
3424 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003425 CONVERT_DOUBLE_CHECKED(value, args[0]);
3426 if (isnan(value)) {
3427 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3428 }
3429 if (isinf(value)) {
3430 if (value < 0) {
3431 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3432 }
3433 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3434 }
3435 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3436 int radix = FastD2I(radix_number);
3437 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3438 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003439 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003440 DeleteArray(str);
3441 return result;
3442}
3443
3444
lrn@chromium.org303ada72010-10-27 09:33:13 +00003445static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003446 NoHandleAllocation ha;
3447 ASSERT(args.length() == 2);
3448
3449 CONVERT_DOUBLE_CHECKED(value, args[0]);
3450 if (isnan(value)) {
3451 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3452 }
3453 if (isinf(value)) {
3454 if (value < 0) {
3455 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3456 }
3457 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3458 }
3459 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3460 int f = FastD2I(f_number);
3461 RUNTIME_ASSERT(f >= 0);
3462 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003463 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003464 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003465 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466}
3467
3468
lrn@chromium.org303ada72010-10-27 09:33:13 +00003469static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003470 NoHandleAllocation ha;
3471 ASSERT(args.length() == 2);
3472
3473 CONVERT_DOUBLE_CHECKED(value, args[0]);
3474 if (isnan(value)) {
3475 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3476 }
3477 if (isinf(value)) {
3478 if (value < 0) {
3479 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3480 }
3481 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3482 }
3483 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3484 int f = FastD2I(f_number);
3485 RUNTIME_ASSERT(f >= -1 && f <= 20);
3486 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003487 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003488 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003489 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003490}
3491
3492
lrn@chromium.org303ada72010-10-27 09:33:13 +00003493static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003494 NoHandleAllocation ha;
3495 ASSERT(args.length() == 2);
3496
3497 CONVERT_DOUBLE_CHECKED(value, args[0]);
3498 if (isnan(value)) {
3499 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3500 }
3501 if (isinf(value)) {
3502 if (value < 0) {
3503 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3504 }
3505 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3506 }
3507 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3508 int f = FastD2I(f_number);
3509 RUNTIME_ASSERT(f >= 1 && f <= 21);
3510 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003511 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003512 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003513 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003514}
3515
3516
3517// Returns a single character string where first character equals
3518// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003519static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003520 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003521 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003522 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003523 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003524 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003525 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003526}
3527
3528
lrn@chromium.org303ada72010-10-27 09:33:13 +00003529MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3530 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003531 // Handle [] indexing on Strings
3532 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003533 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3534 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003535 }
3536
3537 // Handle [] indexing on String objects
3538 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003539 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3540 Handle<Object> result =
3541 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3542 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003543 }
3544
3545 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003546 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003547 return prototype->GetElement(index);
3548 }
3549
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003550 return GetElement(object, index);
3551}
3552
3553
lrn@chromium.org303ada72010-10-27 09:33:13 +00003554MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003555 return object->GetElement(index);
3556}
3557
3558
lrn@chromium.org303ada72010-10-27 09:33:13 +00003559MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3560 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003561 HandleScope scope;
3562
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003563 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003564 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003565 Handle<Object> error =
3566 Factory::NewTypeError("non_object_property_load",
3567 HandleVector(args, 2));
3568 return Top::Throw(*error);
3569 }
3570
3571 // Check if the given key is an array index.
3572 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003573 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003574 return GetElementOrCharAt(object, index);
3575 }
3576
3577 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003578 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003580 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003582 bool has_pending_exception = false;
3583 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003584 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003585 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003586 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003587 }
3588
ager@chromium.org32912102009-01-16 10:38:43 +00003589 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003590 // the element if so.
3591 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 return GetElementOrCharAt(object, index);
3593 } else {
3594 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003595 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 }
3597}
3598
3599
lrn@chromium.org303ada72010-10-27 09:33:13 +00003600static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003601 NoHandleAllocation ha;
3602 ASSERT(args.length() == 2);
3603
3604 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003605 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606
3607 return Runtime::GetObjectProperty(object, key);
3608}
3609
3610
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003611// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003612static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003613 NoHandleAllocation ha;
3614 ASSERT(args.length() == 2);
3615
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003616 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003617 // itself.
3618 //
3619 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003620 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003621 // global proxy object never has properties. This is the case
3622 // because the global proxy object forwards everything to its hidden
3623 // prototype including local lookups.
3624 //
3625 // Additionally, we need to make sure that we do not cache results
3626 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003627 if (args[0]->IsJSObject() &&
3628 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003629 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003630 args[1]->IsString()) {
3631 JSObject* receiver = JSObject::cast(args[0]);
3632 String* key = String::cast(args[1]);
3633 if (receiver->HasFastProperties()) {
3634 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003635 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003636 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3637 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003638 Object* value = receiver->FastPropertyAt(offset);
3639 return value->IsTheHole() ? Heap::undefined_value() : value;
3640 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003641 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003642 LookupResult result;
3643 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003644 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003645 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003646 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003647 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003648 }
3649 } else {
3650 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003651 StringDictionary* dictionary = receiver->property_dictionary();
3652 int entry = dictionary->FindEntry(key);
3653 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003654 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003655 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003656 if (!receiver->IsGlobalObject()) return value;
3657 value = JSGlobalPropertyCell::cast(value)->value();
3658 if (!value->IsTheHole()) return value;
3659 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003660 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003661 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003662 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3663 // Fast case for string indexing using [] with a smi index.
3664 HandleScope scope;
3665 Handle<String> str = args.at<String>(0);
3666 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003667 if (index >= 0 && index < str->length()) {
3668 Handle<Object> result = GetCharAt(str, index);
3669 return *result;
3670 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003671 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003672
3673 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003674 return Runtime::GetObjectProperty(args.at<Object>(0),
3675 args.at<Object>(1));
3676}
3677
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003678// Implements part of 8.12.9 DefineOwnProperty.
3679// There are 3 cases that lead here:
3680// Step 4b - define a new accessor property.
3681// Steps 9c & 12 - replace an existing data property with an accessor property.
3682// Step 12 - update an existing accessor property with an accessor or generic
3683// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003684static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003685 ASSERT(args.length() == 5);
3686 HandleScope scope;
3687 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3688 CONVERT_CHECKED(String, name, args[1]);
3689 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003690 Object* fun = args[3];
3691 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003692 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3693 int unchecked = flag_attr->value();
3694 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3695 RUNTIME_ASSERT(!obj->IsNull());
3696 LookupResult result;
3697 obj->LocalLookupRealNamedProperty(name, &result);
3698
3699 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3700 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3701 // delete it to avoid running into trouble in DefineAccessor, which
3702 // handles this incorrectly if the property is readonly (does nothing)
3703 if (result.IsProperty() &&
3704 (result.type() == FIELD || result.type() == NORMAL
3705 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003706 Object* ok;
3707 { MaybeObject* maybe_ok =
3708 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3709 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3710 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003711 }
3712 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3713}
3714
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003715// Implements part of 8.12.9 DefineOwnProperty.
3716// There are 3 cases that lead here:
3717// Step 4a - define a new data property.
3718// Steps 9b & 12 - replace an existing accessor property with a data property.
3719// Step 12 - update an existing data property with a data or generic
3720// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003721static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003722 ASSERT(args.length() == 4);
3723 HandleScope scope;
3724 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3725 CONVERT_ARG_CHECKED(String, name, 1);
3726 Handle<Object> obj_value = args.at<Object>(2);
3727
3728 CONVERT_CHECKED(Smi, flag, args[3]);
3729 int unchecked = flag->value();
3730 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3731
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003732 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3733
3734 // Check if this is an element.
3735 uint32_t index;
3736 bool is_element = name->AsArrayIndex(&index);
3737
3738 // Special case for elements if any of the flags are true.
3739 // If elements are in fast case we always implicitly assume that:
3740 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3741 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3742 is_element) {
3743 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003744 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003745 // We do not need to do access checks here since these has already
3746 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003747 Handle<Object> proto(js_object->GetPrototype());
3748 // If proxy is detached, ignore the assignment. Alternatively,
3749 // we could throw an exception.
3750 if (proto->IsNull()) return *obj_value;
3751 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003752 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003753 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003754 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003755 // Make sure that we never go back to fast case.
3756 dictionary->set_requires_slow_elements();
3757 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003758 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003759 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003760 }
3761
ager@chromium.org5c838252010-02-19 08:53:10 +00003762 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003763 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003764
ager@chromium.org5c838252010-02-19 08:53:10 +00003765 // Take special care when attributes are different and there is already
3766 // a property. For simplicity we normalize the property which enables us
3767 // to not worry about changing the instance_descriptor and creating a new
3768 // map. The current version of SetObjectProperty does not handle attributes
3769 // correctly in the case where a property is a field and is reset with
3770 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003771 if (result.IsProperty() &&
3772 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003773 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003774 if (js_object->IsJSGlobalProxy()) {
3775 // Since the result is a property, the prototype will exist so
3776 // we don't have to check for null.
3777 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003778 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003779 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003780 // Use IgnoreAttributes version since a readonly property may be
3781 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003782 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3783 *obj_value,
3784 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003785 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003786
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003787 return Runtime::ForceSetObjectProperty(js_object, name, obj_value, attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003788}
3789
3790
lrn@chromium.org303ada72010-10-27 09:33:13 +00003791MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3792 Handle<Object> key,
3793 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003794 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003795 StrictModeFlag strict_mode) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003796 HandleScope scope;
3797
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003798 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003799 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003800 Handle<Object> error =
3801 Factory::NewTypeError("non_object_property_store",
3802 HandleVector(args, 2));
3803 return Top::Throw(*error);
3804 }
3805
3806 // If the object isn't a JavaScript object, we ignore the store.
3807 if (!object->IsJSObject()) return *value;
3808
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003809 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3810
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003811 // Check if the given key is an array index.
3812 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003813 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003814 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3815 // of a string using [] notation. We need to support this too in
3816 // JavaScript.
3817 // In the case of a String object we just need to redirect the assignment to
3818 // the underlying string if the index is in range. Since the underlying
3819 // string does nothing with the assignment then we can ignore such
3820 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003821 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003822 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003823 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003824
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003825 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003826 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003827 return *value;
3828 }
3829
3830 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003831 Handle<Object> result;
3832 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003833 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003834 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003835 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003836 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003837 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003838 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003839 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003840 return *value;
3841 }
3842
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003843 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003844 bool has_pending_exception = false;
3845 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3846 if (has_pending_exception) return Failure::Exception();
3847 Handle<String> name = Handle<String>::cast(converted);
3848
3849 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003850 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003851 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003852 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003853 }
3854}
3855
3856
lrn@chromium.org303ada72010-10-27 09:33:13 +00003857MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3858 Handle<Object> key,
3859 Handle<Object> value,
3860 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003861 HandleScope scope;
3862
3863 // Check if the given key is an array index.
3864 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003865 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003866 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3867 // of a string using [] notation. We need to support this too in
3868 // JavaScript.
3869 // In the case of a String object we just need to redirect the assignment to
3870 // the underlying string if the index is in range. Since the underlying
3871 // string does nothing with the assignment then we can ignore such
3872 // assignments.
3873 if (js_object->IsStringObjectWithCharacterAt(index)) {
3874 return *value;
3875 }
3876
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003877 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003878 }
3879
3880 if (key->IsString()) {
3881 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003882 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003883 } else {
3884 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003885 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003886 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
3887 *value,
3888 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003889 }
3890 }
3891
3892 // Call-back into JavaScript to convert the key to a string.
3893 bool has_pending_exception = false;
3894 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3895 if (has_pending_exception) return Failure::Exception();
3896 Handle<String> name = Handle<String>::cast(converted);
3897
3898 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003899 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003900 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003901 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003902 }
3903}
3904
3905
lrn@chromium.org303ada72010-10-27 09:33:13 +00003906MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3907 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003908 HandleScope scope;
3909
3910 // Check if the given key is an array index.
3911 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003912 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003913 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3914 // characters of a string using [] notation. In the case of a
3915 // String object we just need to redirect the deletion to the
3916 // underlying string if the index is in range. Since the
3917 // underlying string does nothing with the deletion, we can ignore
3918 // such deletions.
3919 if (js_object->IsStringObjectWithCharacterAt(index)) {
3920 return Heap::true_value();
3921 }
3922
3923 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3924 }
3925
3926 Handle<String> key_string;
3927 if (key->IsString()) {
3928 key_string = Handle<String>::cast(key);
3929 } else {
3930 // Call-back into JavaScript to convert the key to a string.
3931 bool has_pending_exception = false;
3932 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3933 if (has_pending_exception) return Failure::Exception();
3934 key_string = Handle<String>::cast(converted);
3935 }
3936
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003937 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003938 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3939}
3940
3941
lrn@chromium.org303ada72010-10-27 09:33:13 +00003942static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003943 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003944 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003945
3946 Handle<Object> object = args.at<Object>(0);
3947 Handle<Object> key = args.at<Object>(1);
3948 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003949 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
3950 RUNTIME_ASSERT(
3951 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003952 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003953 PropertyAttributes attributes =
3954 static_cast<PropertyAttributes>(unchecked_attributes);
3955
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003956 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003957 if (args.length() == 5) {
3958 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
3959 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
3960 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003961 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003962 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003963
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003964 return Runtime::SetObjectProperty(object,
3965 key,
3966 value,
3967 attributes,
3968 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969}
3970
3971
3972// Set a local property, even if it is READ_ONLY. If the property does not
3973// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003974static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003975 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003976 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 CONVERT_CHECKED(JSObject, object, args[0]);
3978 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003979 // Compute attributes.
3980 PropertyAttributes attributes = NONE;
3981 if (args.length() == 4) {
3982 CONVERT_CHECKED(Smi, value_obj, args[3]);
3983 int unchecked_value = value_obj->value();
3984 // Only attribute bits should be set.
3985 RUNTIME_ASSERT(
3986 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3987 attributes = static_cast<PropertyAttributes>(unchecked_value);
3988 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003989
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003990 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003991 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003992}
3993
3994
lrn@chromium.org303ada72010-10-27 09:33:13 +00003995static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003996 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003997 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998
3999 CONVERT_CHECKED(JSObject, object, args[0]);
4000 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004001 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004002 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004003 ? JSObject::STRICT_DELETION
4004 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004005}
4006
4007
ager@chromium.org9085a012009-05-11 19:22:57 +00004008static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
4009 Handle<String> key) {
4010 if (object->HasLocalProperty(*key)) return Heap::true_value();
4011 // Handle hidden prototypes. If there's a hidden prototype above this thing
4012 // then we have to check it for properties, because they are supposed to
4013 // look like they are on this object.
4014 Handle<Object> proto(object->GetPrototype());
4015 if (proto->IsJSObject() &&
4016 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
4017 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
4018 }
4019 return Heap::false_value();
4020}
4021
4022
lrn@chromium.org303ada72010-10-27 09:33:13 +00004023static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004024 NoHandleAllocation ha;
4025 ASSERT(args.length() == 2);
4026 CONVERT_CHECKED(String, key, args[1]);
4027
ager@chromium.org9085a012009-05-11 19:22:57 +00004028 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004030 if (obj->IsJSObject()) {
4031 JSObject* object = JSObject::cast(obj);
4032 // Fast case - no interceptors.
4033 if (object->HasRealNamedProperty(key)) return Heap::true_value();
4034 // Slow case. Either it's not there or we have an interceptor. We should
4035 // have handles for this kind of deal.
4036 HandleScope scope;
4037 return HasLocalPropertyImplementation(Handle<JSObject>(object),
4038 Handle<String>(key));
4039 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040 // Well, there is one exception: Handle [] on strings.
4041 uint32_t index;
4042 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004043 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004044 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 return Heap::true_value();
4046 }
4047 }
4048 return Heap::false_value();
4049}
4050
4051
lrn@chromium.org303ada72010-10-27 09:33:13 +00004052static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 NoHandleAllocation na;
4054 ASSERT(args.length() == 2);
4055
4056 // Only JS objects can have properties.
4057 if (args[0]->IsJSObject()) {
4058 JSObject* object = JSObject::cast(args[0]);
4059 CONVERT_CHECKED(String, key, args[1]);
4060 if (object->HasProperty(key)) return Heap::true_value();
4061 }
4062 return Heap::false_value();
4063}
4064
4065
lrn@chromium.org303ada72010-10-27 09:33:13 +00004066static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 NoHandleAllocation na;
4068 ASSERT(args.length() == 2);
4069
4070 // Only JS objects can have elements.
4071 if (args[0]->IsJSObject()) {
4072 JSObject* object = JSObject::cast(args[0]);
4073 CONVERT_CHECKED(Smi, index_obj, args[1]);
4074 uint32_t index = index_obj->value();
4075 if (object->HasElement(index)) return Heap::true_value();
4076 }
4077 return Heap::false_value();
4078}
4079
4080
lrn@chromium.org303ada72010-10-27 09:33:13 +00004081static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 NoHandleAllocation ha;
4083 ASSERT(args.length() == 2);
4084
4085 CONVERT_CHECKED(JSObject, object, args[0]);
4086 CONVERT_CHECKED(String, key, args[1]);
4087
4088 uint32_t index;
4089 if (key->AsArrayIndex(&index)) {
4090 return Heap::ToBoolean(object->HasElement(index));
4091 }
4092
ager@chromium.org870a0b62008-11-04 11:43:05 +00004093 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
4094 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004095}
4096
4097
lrn@chromium.org303ada72010-10-27 09:33:13 +00004098static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 HandleScope scope;
4100 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004101 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 return *GetKeysFor(object);
4103}
4104
4105
4106// Returns either a FixedArray as Runtime_GetPropertyNames,
4107// or, if the given object has an enum cache that contains
4108// all enumerable properties of the object and its prototypes
4109// have none, the map of the object. This is used to speed up
4110// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004111static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 ASSERT(args.length() == 1);
4113
4114 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4115
4116 if (raw_object->IsSimpleEnum()) return raw_object->map();
4117
4118 HandleScope scope;
4119 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004120 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4121 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004122
4123 // Test again, since cache may have been built by preceding call.
4124 if (object->IsSimpleEnum()) return object->map();
4125
4126 return *content;
4127}
4128
4129
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004130// Find the length of the prototype chain that is to to handled as one. If a
4131// prototype object is hidden it is to be viewed as part of the the object it
4132// is prototype for.
4133static int LocalPrototypeChainLength(JSObject* obj) {
4134 int count = 1;
4135 Object* proto = obj->GetPrototype();
4136 while (proto->IsJSObject() &&
4137 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4138 count++;
4139 proto = JSObject::cast(proto)->GetPrototype();
4140 }
4141 return count;
4142}
4143
4144
4145// Return the names of the local named properties.
4146// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004147static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004148 HandleScope scope;
4149 ASSERT(args.length() == 1);
4150 if (!args[0]->IsJSObject()) {
4151 return Heap::undefined_value();
4152 }
4153 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4154
4155 // Skip the global proxy as it has no properties and always delegates to the
4156 // real global object.
4157 if (obj->IsJSGlobalProxy()) {
4158 // Only collect names if access is permitted.
4159 if (obj->IsAccessCheckNeeded() &&
4160 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
4161 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4162 return *Factory::NewJSArray(0);
4163 }
4164 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4165 }
4166
4167 // Find the number of objects making up this.
4168 int length = LocalPrototypeChainLength(*obj);
4169
4170 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004171 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004172 int total_property_count = 0;
4173 Handle<JSObject> jsproto = obj;
4174 for (int i = 0; i < length; i++) {
4175 // Only collect names if access is permitted.
4176 if (jsproto->IsAccessCheckNeeded() &&
4177 !Top::MayNamedAccess(*jsproto,
4178 Heap::undefined_value(),
4179 v8::ACCESS_KEYS)) {
4180 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4181 return *Factory::NewJSArray(0);
4182 }
4183 int n;
4184 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4185 local_property_count[i] = n;
4186 total_property_count += n;
4187 if (i < length - 1) {
4188 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4189 }
4190 }
4191
4192 // Allocate an array with storage for all the property names.
4193 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4194
4195 // Get the property names.
4196 jsproto = obj;
4197 int proto_with_hidden_properties = 0;
4198 for (int i = 0; i < length; i++) {
4199 jsproto->GetLocalPropertyNames(*names,
4200 i == 0 ? 0 : local_property_count[i - 1]);
4201 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4202 proto_with_hidden_properties++;
4203 }
4204 if (i < length - 1) {
4205 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4206 }
4207 }
4208
4209 // Filter out name of hidden propeties object.
4210 if (proto_with_hidden_properties > 0) {
4211 Handle<FixedArray> old_names = names;
4212 names = Factory::NewFixedArray(
4213 names->length() - proto_with_hidden_properties);
4214 int dest_pos = 0;
4215 for (int i = 0; i < total_property_count; i++) {
4216 Object* name = old_names->get(i);
4217 if (name == Heap::hidden_symbol()) {
4218 continue;
4219 }
4220 names->set(dest_pos++, name);
4221 }
4222 }
4223
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004224 return *Factory::NewJSArrayWithElements(names);
4225}
4226
4227
4228// Return the names of the local indexed properties.
4229// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004230static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004231 HandleScope scope;
4232 ASSERT(args.length() == 1);
4233 if (!args[0]->IsJSObject()) {
4234 return Heap::undefined_value();
4235 }
4236 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4237
4238 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4239 Handle<FixedArray> names = Factory::NewFixedArray(n);
4240 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4241 return *Factory::NewJSArrayWithElements(names);
4242}
4243
4244
4245// Return information on whether an object has a named or indexed interceptor.
4246// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004247static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004248 HandleScope scope;
4249 ASSERT(args.length() == 1);
4250 if (!args[0]->IsJSObject()) {
4251 return Smi::FromInt(0);
4252 }
4253 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4254
4255 int result = 0;
4256 if (obj->HasNamedInterceptor()) result |= 2;
4257 if (obj->HasIndexedInterceptor()) result |= 1;
4258
4259 return Smi::FromInt(result);
4260}
4261
4262
4263// Return property names from named interceptor.
4264// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004265static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004266 HandleScope scope;
4267 ASSERT(args.length() == 1);
4268 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4269
4270 if (obj->HasNamedInterceptor()) {
4271 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4272 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4273 }
4274 return Heap::undefined_value();
4275}
4276
4277
4278// Return element names from indexed interceptor.
4279// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004280static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004281 HandleScope scope;
4282 ASSERT(args.length() == 1);
4283 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4284
4285 if (obj->HasIndexedInterceptor()) {
4286 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4287 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4288 }
4289 return Heap::undefined_value();
4290}
4291
4292
lrn@chromium.org303ada72010-10-27 09:33:13 +00004293static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004294 ASSERT_EQ(args.length(), 1);
4295 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4296 HandleScope scope;
4297 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004298
4299 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004300 // Do access checks before going to the global object.
4301 if (object->IsAccessCheckNeeded() &&
4302 !Top::MayNamedAccess(*object, Heap::undefined_value(),
4303 v8::ACCESS_KEYS)) {
4304 Top::ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4305 return *Factory::NewJSArray(0);
4306 }
4307
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004308 Handle<Object> proto(object->GetPrototype());
4309 // If proxy is detached we simply return an empty array.
4310 if (proto->IsNull()) return *Factory::NewJSArray(0);
4311 object = Handle<JSObject>::cast(proto);
4312 }
4313
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004314 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4315 LOCAL_ONLY);
4316 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4317 // property array and since the result is mutable we have to create
4318 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004319 int length = contents->length();
4320 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4321 for (int i = 0; i < length; i++) {
4322 Object* entry = contents->get(i);
4323 if (entry->IsString()) {
4324 copy->set(i, entry);
4325 } else {
4326 ASSERT(entry->IsNumber());
4327 HandleScope scope;
4328 Handle<Object> entry_handle(entry);
4329 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4330 copy->set(i, *entry_str);
4331 }
4332 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004333 return *Factory::NewJSArrayWithElements(copy);
4334}
4335
4336
lrn@chromium.org303ada72010-10-27 09:33:13 +00004337static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004338 NoHandleAllocation ha;
4339 ASSERT(args.length() == 1);
4340
4341 // Compute the frame holding the arguments.
4342 JavaScriptFrameIterator it;
4343 it.AdvanceToArgumentsFrame();
4344 JavaScriptFrame* frame = it.frame();
4345
4346 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004347 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004348
4349 // Try to convert the key to an index. If successful and within
4350 // index return the the argument from the frame.
4351 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004352 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004353 return frame->GetParameter(index);
4354 }
4355
4356 // Convert the key to a string.
4357 HandleScope scope;
4358 bool exception = false;
4359 Handle<Object> converted =
4360 Execution::ToString(args.at<Object>(0), &exception);
4361 if (exception) return Failure::Exception();
4362 Handle<String> key = Handle<String>::cast(converted);
4363
4364 // Try to convert the string key into an array index.
4365 if (key->AsArrayIndex(&index)) {
4366 if (index < n) {
4367 return frame->GetParameter(index);
4368 } else {
4369 return Top::initial_object_prototype()->GetElement(index);
4370 }
4371 }
4372
4373 // Handle special arguments properties.
4374 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4375 if (key->Equals(Heap::callee_symbol())) return frame->function();
4376
4377 // Lookup in the initial Object.prototype object.
4378 return Top::initial_object_prototype()->GetProperty(*key);
4379}
4380
4381
lrn@chromium.org303ada72010-10-27 09:33:13 +00004382static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004383 HandleScope scope;
4384
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004385 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004386 Handle<Object> object = args.at<Object>(0);
4387 if (object->IsJSObject()) {
4388 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004389 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004390 MaybeObject* ok = js_object->TransformToFastProperties(0);
4391 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004392 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004393 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004394 return *object;
4395}
4396
4397
lrn@chromium.org303ada72010-10-27 09:33:13 +00004398static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004399 HandleScope scope;
4400
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004401 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004402 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004403 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004404 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004405 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004406 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004407 return *object;
4408}
4409
4410
lrn@chromium.org303ada72010-10-27 09:33:13 +00004411static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004412 NoHandleAllocation ha;
4413 ASSERT(args.length() == 1);
4414
4415 return args[0]->ToBoolean();
4416}
4417
4418
4419// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4420// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004421static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422 NoHandleAllocation ha;
4423
4424 Object* obj = args[0];
4425 if (obj->IsNumber()) return Heap::number_symbol();
4426 HeapObject* heap_obj = HeapObject::cast(obj);
4427
4428 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004429 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004430
4431 InstanceType instance_type = heap_obj->map()->instance_type();
4432 if (instance_type < FIRST_NONSTRING_TYPE) {
4433 return Heap::string_symbol();
4434 }
4435
4436 switch (instance_type) {
4437 case ODDBALL_TYPE:
4438 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4439 return Heap::boolean_symbol();
4440 }
4441 if (heap_obj->IsNull()) {
4442 return Heap::object_symbol();
4443 }
4444 ASSERT(heap_obj->IsUndefined());
4445 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004446 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004447 return Heap::function_symbol();
4448 default:
4449 // For any kind of object not handled above, the spec rule for
4450 // host objects gives that it is okay to return "object"
4451 return Heap::object_symbol();
4452 }
4453}
4454
4455
lrn@chromium.org25156de2010-04-06 13:10:27 +00004456static bool AreDigits(const char*s, int from, int to) {
4457 for (int i = from; i < to; i++) {
4458 if (s[i] < '0' || s[i] > '9') return false;
4459 }
4460
4461 return true;
4462}
4463
4464
4465static int ParseDecimalInteger(const char*s, int from, int to) {
4466 ASSERT(to - from < 10); // Overflow is not possible.
4467 ASSERT(from < to);
4468 int d = s[from] - '0';
4469
4470 for (int i = from + 1; i < to; i++) {
4471 d = 10 * d + (s[i] - '0');
4472 }
4473
4474 return d;
4475}
4476
4477
lrn@chromium.org303ada72010-10-27 09:33:13 +00004478static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004479 NoHandleAllocation ha;
4480 ASSERT(args.length() == 1);
4481 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004482 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004483
4484 // Fast case: short integer or some sorts of junk values.
4485 int len = subject->length();
4486 if (subject->IsSeqAsciiString()) {
4487 if (len == 0) return Smi::FromInt(0);
4488
4489 char const* data = SeqAsciiString::cast(subject)->GetChars();
4490 bool minus = (data[0] == '-');
4491 int start_pos = (minus ? 1 : 0);
4492
4493 if (start_pos == len) {
4494 return Heap::nan_value();
4495 } else if (data[start_pos] > '9') {
4496 // Fast check for a junk value. A valid string may start from a
4497 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4498 // the 'I' character ('Infinity'). All of that have codes not greater than
4499 // '9' except 'I'.
4500 if (data[start_pos] != 'I') {
4501 return Heap::nan_value();
4502 }
4503 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4504 // The maximal/minimal smi has 10 digits. If the string has less digits we
4505 // know it will fit into the smi-data type.
4506 int d = ParseDecimalInteger(data, start_pos, len);
4507 if (minus) {
4508 if (d == 0) return Heap::minus_zero_value();
4509 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004510 } else if (!subject->HasHashCode() &&
4511 len <= String::kMaxArrayIndexSize &&
4512 (len == 1 || data[0] != '0')) {
4513 // String hash is not calculated yet but all the data are present.
4514 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004515 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004516#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004517 subject->Hash(); // Force hash calculation.
4518 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4519 static_cast<int>(hash));
4520#endif
4521 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004522 }
4523 return Smi::FromInt(d);
4524 }
4525 }
4526
4527 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004528 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4529}
4530
4531
lrn@chromium.org303ada72010-10-27 09:33:13 +00004532static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533 NoHandleAllocation ha;
4534 ASSERT(args.length() == 1);
4535
4536 CONVERT_CHECKED(JSArray, codes, args[0]);
4537 int length = Smi::cast(codes->length())->value();
4538
4539 // Check if the string can be ASCII.
4540 int i;
4541 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004542 Object* element;
4543 { MaybeObject* maybe_element = codes->GetElement(i);
4544 // We probably can't get an exception here, but just in order to enforce
4545 // the checking of inputs in the runtime calls we check here.
4546 if (!maybe_element->ToObject(&element)) return maybe_element;
4547 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004548 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4549 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4550 break;
4551 }
4552
lrn@chromium.org303ada72010-10-27 09:33:13 +00004553 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004554 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004555 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004556 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004557 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004558 }
4559
lrn@chromium.org303ada72010-10-27 09:33:13 +00004560 Object* object = NULL;
4561 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004562 String* result = String::cast(object);
4563 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004564 Object* element;
4565 { MaybeObject* maybe_element = codes->GetElement(i);
4566 if (!maybe_element->ToObject(&element)) return maybe_element;
4567 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004568 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004569 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004570 }
4571 return result;
4572}
4573
4574
4575// kNotEscaped is generated by the following:
4576//
4577// #!/bin/perl
4578// for (my $i = 0; $i < 256; $i++) {
4579// print "\n" if $i % 16 == 0;
4580// my $c = chr($i);
4581// my $escaped = 1;
4582// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4583// print $escaped ? "0, " : "1, ";
4584// }
4585
4586
4587static bool IsNotEscaped(uint16_t character) {
4588 // Only for 8 bit characters, the rest are always escaped (in a different way)
4589 ASSERT(character < 256);
4590 static const char kNotEscaped[256] = {
4591 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4592 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4593 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4594 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4595 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4596 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4597 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4598 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4599 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4600 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4601 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4602 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4603 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4604 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4605 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4606 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4607 };
4608 return kNotEscaped[character] != 0;
4609}
4610
4611
lrn@chromium.org303ada72010-10-27 09:33:13 +00004612static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004613 const char hex_chars[] = "0123456789ABCDEF";
4614 NoHandleAllocation ha;
4615 ASSERT(args.length() == 1);
4616 CONVERT_CHECKED(String, source, args[0]);
4617
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004618 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004619
4620 int escaped_length = 0;
4621 int length = source->length();
4622 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004623 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004624 buffer->Reset(source);
4625 while (buffer->has_more()) {
4626 uint16_t character = buffer->GetNext();
4627 if (character >= 256) {
4628 escaped_length += 6;
4629 } else if (IsNotEscaped(character)) {
4630 escaped_length++;
4631 } else {
4632 escaped_length += 3;
4633 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004634 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004635 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004636 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004637 Top::context()->mark_out_of_memory();
4638 return Failure::OutOfMemoryException();
4639 }
4640 }
4641 }
4642 // No length change implies no change. Return original string if no change.
4643 if (escaped_length == length) {
4644 return source;
4645 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004646 Object* o;
4647 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4648 if (!maybe_o->ToObject(&o)) return maybe_o;
4649 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004650 String* destination = String::cast(o);
4651 int dest_position = 0;
4652
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004653 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004654 buffer->Rewind();
4655 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004656 uint16_t chr = buffer->GetNext();
4657 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004658 destination->Set(dest_position, '%');
4659 destination->Set(dest_position+1, 'u');
4660 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4661 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4662 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4663 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004664 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004665 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004666 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004667 dest_position++;
4668 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004669 destination->Set(dest_position, '%');
4670 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4671 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004672 dest_position += 3;
4673 }
4674 }
4675 return destination;
4676}
4677
4678
4679static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4680 static const signed char kHexValue['g'] = {
4681 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4682 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4683 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4684 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4685 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4686 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4687 -1, 10, 11, 12, 13, 14, 15 };
4688
4689 if (character1 > 'f') return -1;
4690 int hi = kHexValue[character1];
4691 if (hi == -1) return -1;
4692 if (character2 > 'f') return -1;
4693 int lo = kHexValue[character2];
4694 if (lo == -1) return -1;
4695 return (hi << 4) + lo;
4696}
4697
4698
ager@chromium.org870a0b62008-11-04 11:43:05 +00004699static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004700 int i,
4701 int length,
4702 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004703 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004704 int32_t hi = 0;
4705 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004706 if (character == '%' &&
4707 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004708 source->Get(i + 1) == 'u' &&
4709 (hi = TwoDigitHex(source->Get(i + 2),
4710 source->Get(i + 3))) != -1 &&
4711 (lo = TwoDigitHex(source->Get(i + 4),
4712 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004713 *step = 6;
4714 return (hi << 8) + lo;
4715 } else if (character == '%' &&
4716 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004717 (lo = TwoDigitHex(source->Get(i + 1),
4718 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004719 *step = 3;
4720 return lo;
4721 } else {
4722 *step = 1;
4723 return character;
4724 }
4725}
4726
4727
lrn@chromium.org303ada72010-10-27 09:33:13 +00004728static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004729 NoHandleAllocation ha;
4730 ASSERT(args.length() == 1);
4731 CONVERT_CHECKED(String, source, args[0]);
4732
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004733 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004734
4735 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004736 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004737
4738 int unescaped_length = 0;
4739 for (int i = 0; i < length; unescaped_length++) {
4740 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004741 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004743 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004744 i += step;
4745 }
4746
4747 // No length change implies no change. Return original string if no change.
4748 if (unescaped_length == length)
4749 return source;
4750
lrn@chromium.org303ada72010-10-27 09:33:13 +00004751 Object* o;
4752 { MaybeObject* maybe_o = ascii ?
4753 Heap::AllocateRawAsciiString(unescaped_length) :
4754 Heap::AllocateRawTwoByteString(unescaped_length);
4755 if (!maybe_o->ToObject(&o)) return maybe_o;
4756 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757 String* destination = String::cast(o);
4758
4759 int dest_position = 0;
4760 for (int i = 0; i < length; dest_position++) {
4761 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004762 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763 i += step;
4764 }
4765 return destination;
4766}
4767
4768
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004769static const unsigned int kQuoteTableLength = 128u;
4770
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004771static const int kJsonQuotesCharactersPerEntry = 8;
4772static const char* const JsonQuotes =
4773 "\\u0000 \\u0001 \\u0002 \\u0003 "
4774 "\\u0004 \\u0005 \\u0006 \\u0007 "
4775 "\\b \\t \\n \\u000b "
4776 "\\f \\r \\u000e \\u000f "
4777 "\\u0010 \\u0011 \\u0012 \\u0013 "
4778 "\\u0014 \\u0015 \\u0016 \\u0017 "
4779 "\\u0018 \\u0019 \\u001a \\u001b "
4780 "\\u001c \\u001d \\u001e \\u001f "
4781 " ! \\\" # "
4782 "$ % & ' "
4783 "( ) * + "
4784 ", - . / "
4785 "0 1 2 3 "
4786 "4 5 6 7 "
4787 "8 9 : ; "
4788 "< = > ? "
4789 "@ A B C "
4790 "D E F G "
4791 "H I J K "
4792 "L M N O "
4793 "P Q R S "
4794 "T U V W "
4795 "X Y Z [ "
4796 "\\\\ ] ^ _ "
4797 "` a b c "
4798 "d e f g "
4799 "h i j k "
4800 "l m n o "
4801 "p q r s "
4802 "t u v w "
4803 "x y z { "
4804 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004805
4806
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004807// For a string that is less than 32k characters it should always be
4808// possible to allocate it in new space.
4809static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4810
4811
4812// Doing JSON quoting cannot make the string more than this many times larger.
4813static const int kJsonQuoteWorstCaseBlowup = 6;
4814
4815
4816// Covers the entire ASCII range (all other characters are unchanged by JSON
4817// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004818static const byte JsonQuoteLengths[kQuoteTableLength] = {
4819 6, 6, 6, 6, 6, 6, 6, 6,
4820 2, 2, 2, 6, 2, 2, 6, 6,
4821 6, 6, 6, 6, 6, 6, 6, 6,
4822 6, 6, 6, 6, 6, 6, 6, 6,
4823 1, 1, 2, 1, 1, 1, 1, 1,
4824 1, 1, 1, 1, 1, 1, 1, 1,
4825 1, 1, 1, 1, 1, 1, 1, 1,
4826 1, 1, 1, 1, 1, 1, 1, 1,
4827 1, 1, 1, 1, 1, 1, 1, 1,
4828 1, 1, 1, 1, 1, 1, 1, 1,
4829 1, 1, 1, 1, 1, 1, 1, 1,
4830 1, 1, 1, 1, 2, 1, 1, 1,
4831 1, 1, 1, 1, 1, 1, 1, 1,
4832 1, 1, 1, 1, 1, 1, 1, 1,
4833 1, 1, 1, 1, 1, 1, 1, 1,
4834 1, 1, 1, 1, 1, 1, 1, 1,
4835};
4836
4837
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004838template <typename StringType>
4839MaybeObject* AllocateRawString(int length);
4840
4841
4842template <>
4843MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4844 return Heap::AllocateRawTwoByteString(length);
4845}
4846
4847
4848template <>
4849MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4850 return Heap::AllocateRawAsciiString(length);
4851}
4852
4853
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004854template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004855static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004856 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004857 const Char* read_cursor = characters.start();
4858 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004859 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004860 int quoted_length = kSpaceForQuotes;
4861 while (read_cursor < end) {
4862 Char c = *(read_cursor++);
4863 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4864 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004865 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004866 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004867 }
4868 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004869 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4870 Object* new_object;
4871 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004872 return new_alloc;
4873 }
4874 StringType* new_string = StringType::cast(new_object);
4875
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004876 Char* write_cursor = reinterpret_cast<Char*>(
4877 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004878 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004879 *(write_cursor++) = '"';
4880
4881 read_cursor = characters.start();
4882 while (read_cursor < end) {
4883 Char c = *(read_cursor++);
4884 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4885 *(write_cursor++) = c;
4886 } else {
4887 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4888 const char* replacement = JsonQuotes +
4889 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4890 for (int i = 0; i < len; i++) {
4891 *write_cursor++ = *replacement++;
4892 }
4893 }
4894 }
4895 *(write_cursor++) = '"';
4896 return new_string;
4897}
4898
4899
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004900template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004901static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4902 int length = characters.length();
4903 Counters::quote_json_char_count.Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004904 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004905 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4906 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004907 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004908 }
4909
4910 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4911 Object* new_object;
4912 if (!new_alloc->ToObject(&new_object)) {
4913 return new_alloc;
4914 }
4915 if (!Heap::new_space()->Contains(new_object)) {
4916 // Even if our string is small enough to fit in new space we still have to
4917 // handle it being allocated in old space as may happen in the third
4918 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4919 // CEntryStub::GenerateCore.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004920 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004921 }
4922 StringType* new_string = StringType::cast(new_object);
4923 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004924
4925 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4926 Char* write_cursor = reinterpret_cast<Char*>(
4927 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004928 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004929 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004930
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004931 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004932 const Char* end = read_cursor + length;
4933 while (read_cursor < end) {
4934 Char c = *(read_cursor++);
4935 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4936 *(write_cursor++) = c;
4937 } else {
4938 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4939 const char* replacement = JsonQuotes +
4940 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4941 write_cursor[0] = replacement[0];
4942 if (len > 1) {
4943 write_cursor[1] = replacement[1];
4944 if (len > 2) {
4945 ASSERT(len == 6);
4946 write_cursor[2] = replacement[2];
4947 write_cursor[3] = replacement[3];
4948 write_cursor[4] = replacement[4];
4949 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004950 }
4951 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004952 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004953 }
4954 }
4955 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004956
4957 int final_length = static_cast<int>(
4958 write_cursor - reinterpret_cast<Char*>(
4959 new_string->address() + SeqAsciiString::kHeaderSize));
4960 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4961 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004962 return new_string;
4963}
4964
4965
4966static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4967 NoHandleAllocation ha;
4968 CONVERT_CHECKED(String, str, args[0]);
4969 if (!str->IsFlat()) {
4970 MaybeObject* try_flatten = str->TryFlatten();
4971 Object* flat;
4972 if (!try_flatten->ToObject(&flat)) {
4973 return try_flatten;
4974 }
4975 str = String::cast(flat);
4976 ASSERT(str->IsFlat());
4977 }
4978 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004979 return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004980 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004981 return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004982 }
4983}
4984
4985
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004986static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
4987 NoHandleAllocation ha;
4988 CONVERT_CHECKED(String, str, args[0]);
4989 if (!str->IsFlat()) {
4990 MaybeObject* try_flatten = str->TryFlatten();
4991 Object* flat;
4992 if (!try_flatten->ToObject(&flat)) {
4993 return try_flatten;
4994 }
4995 str = String::cast(flat);
4996 ASSERT(str->IsFlat());
4997 }
4998 if (str->IsTwoByteRepresentation()) {
4999 return QuoteJsonString<uc16, SeqTwoByteString, true>(str->ToUC16Vector());
5000 } else {
5001 return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
5002 }
5003}
5004
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005005
lrn@chromium.org303ada72010-10-27 09:33:13 +00005006static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005007 NoHandleAllocation ha;
5008
5009 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005010 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005011
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005012 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005013
lrn@chromium.org25156de2010-04-06 13:10:27 +00005014 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
5015 double value = StringToInt(s, radix);
5016 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005017}
5018
5019
lrn@chromium.org303ada72010-10-27 09:33:13 +00005020static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005021 NoHandleAllocation ha;
5022 CONVERT_CHECKED(String, str, args[0]);
5023
5024 // ECMA-262 section 15.1.2.3, empty string is NaN
5025 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
5026
5027 // Create a number object from the value.
5028 return Heap::NumberFromDouble(value);
5029}
5030
5031
5032static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
5033static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
5034
5035
5036template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005037MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
5038 String* s,
5039 int length,
5040 int input_string_length,
5041 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005042 // We try this twice, once with the assumption that the result is no longer
5043 // than the input and, if that assumption breaks, again with the exact
5044 // length. This may not be pretty, but it is nicer than what was here before
5045 // and I hereby claim my vaffel-is.
5046 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005047 // Allocate the resulting string.
5048 //
5049 // NOTE: This assumes that the upper/lower case of an ascii
5050 // character is also ascii. This is currently the case, but it
5051 // might break in the future if we implement more context and locale
5052 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005053 Object* o;
5054 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
5055 ? Heap::AllocateRawAsciiString(length)
5056 : Heap::AllocateRawTwoByteString(length);
5057 if (!maybe_o->ToObject(&o)) return maybe_o;
5058 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005059 String* result = String::cast(o);
5060 bool has_changed_character = false;
5061
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005062 // Convert all characters to upper case, assuming that they will fit
5063 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005064 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005065 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005066 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005067 // We can assume that the string is not empty
5068 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005069 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005070 bool has_next = buffer->has_more();
5071 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005072 int char_length = mapping->get(current, next, chars);
5073 if (char_length == 0) {
5074 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005075 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005076 i++;
5077 } else if (char_length == 1) {
5078 // Common case: converting the letter resulted in one character.
5079 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005080 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005081 has_changed_character = true;
5082 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005083 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005084 // We've assumed that the result would be as long as the
5085 // input but here is a character that converts to several
5086 // characters. No matter, we calculate the exact length
5087 // of the result and try the whole thing again.
5088 //
5089 // Note that this leaves room for optimization. We could just
5090 // memcpy what we already have to the result string. Also,
5091 // the result string is the last object allocated we could
5092 // "realloc" it and probably, in the vast majority of cases,
5093 // extend the existing string to be able to hold the full
5094 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005095 int next_length = 0;
5096 if (has_next) {
5097 next_length = mapping->get(next, 0, chars);
5098 if (next_length == 0) next_length = 1;
5099 }
5100 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005101 while (buffer->has_more()) {
5102 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005103 // NOTE: we use 0 as the next character here because, while
5104 // the next character may affect what a character converts to,
5105 // it does not in any case affect the length of what it convert
5106 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005107 int char_length = mapping->get(current, 0, chars);
5108 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005109 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005110 if (current_length > Smi::kMaxValue) {
5111 Top::context()->mark_out_of_memory();
5112 return Failure::OutOfMemoryException();
5113 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005114 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005115 // Try again with the real length.
5116 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005117 } else {
5118 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005119 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005120 i++;
5121 }
5122 has_changed_character = true;
5123 }
5124 current = next;
5125 }
5126 if (has_changed_character) {
5127 return result;
5128 } else {
5129 // If we didn't actually change anything in doing the conversion
5130 // we simple return the result and let the converted string
5131 // become garbage; there is no reason to keep two identical strings
5132 // alive.
5133 return s;
5134 }
5135}
5136
5137
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005138namespace {
5139
lrn@chromium.org303ada72010-10-27 09:33:13 +00005140static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5141
5142
5143// Given a word and two range boundaries returns a word with high bit
5144// set in every byte iff the corresponding input byte was strictly in
5145// the range (m, n). All the other bits in the result are cleared.
5146// This function is only useful when it can be inlined and the
5147// boundaries are statically known.
5148// Requires: all bytes in the input word and the boundaries must be
5149// ascii (less than 0x7F).
5150static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5151 // Every byte in an ascii string is less than or equal to 0x7F.
5152 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5153 // Use strict inequalities since in edge cases the function could be
5154 // further simplified.
5155 ASSERT(0 < m && m < n && n < 0x7F);
5156 // Has high bit set in every w byte less than n.
5157 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5158 // Has high bit set in every w byte greater than m.
5159 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5160 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5161}
5162
5163
5164enum AsciiCaseConversion {
5165 ASCII_TO_LOWER,
5166 ASCII_TO_UPPER
5167};
5168
5169
5170template <AsciiCaseConversion dir>
5171struct FastAsciiConverter {
5172 static bool Convert(char* dst, char* src, int length) {
5173#ifdef DEBUG
5174 char* saved_dst = dst;
5175 char* saved_src = src;
5176#endif
5177 // We rely on the distance between upper and lower case letters
5178 // being a known power of 2.
5179 ASSERT('a' - 'A' == (1 << 5));
5180 // Boundaries for the range of input characters than require conversion.
5181 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5182 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5183 bool changed = false;
5184 char* const limit = src + length;
5185#ifdef V8_HOST_CAN_READ_UNALIGNED
5186 // Process the prefix of the input that requires no conversion one
5187 // (machine) word at a time.
5188 while (src <= limit - sizeof(uintptr_t)) {
5189 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5190 if (AsciiRangeMask(w, lo, hi) != 0) {
5191 changed = true;
5192 break;
5193 }
5194 *reinterpret_cast<uintptr_t*>(dst) = w;
5195 src += sizeof(uintptr_t);
5196 dst += sizeof(uintptr_t);
5197 }
5198 // Process the remainder of the input performing conversion when
5199 // required one word at a time.
5200 while (src <= limit - sizeof(uintptr_t)) {
5201 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5202 uintptr_t m = AsciiRangeMask(w, lo, hi);
5203 // The mask has high (7th) bit set in every byte that needs
5204 // conversion and we know that the distance between cases is
5205 // 1 << 5.
5206 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5207 src += sizeof(uintptr_t);
5208 dst += sizeof(uintptr_t);
5209 }
5210#endif
5211 // Process the last few bytes of the input (or the whole input if
5212 // unaligned access is not supported).
5213 while (src < limit) {
5214 char c = *src;
5215 if (lo < c && c < hi) {
5216 c ^= (1 << 5);
5217 changed = true;
5218 }
5219 *dst = c;
5220 ++src;
5221 ++dst;
5222 }
5223#ifdef DEBUG
5224 CheckConvert(saved_dst, saved_src, length, changed);
5225#endif
5226 return changed;
5227 }
5228
5229#ifdef DEBUG
5230 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5231 bool expected_changed = false;
5232 for (int i = 0; i < length; i++) {
5233 if (dst[i] == src[i]) continue;
5234 expected_changed = true;
5235 if (dir == ASCII_TO_LOWER) {
5236 ASSERT('A' <= src[i] && src[i] <= 'Z');
5237 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5238 } else {
5239 ASSERT(dir == ASCII_TO_UPPER);
5240 ASSERT('a' <= src[i] && src[i] <= 'z');
5241 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5242 }
5243 }
5244 ASSERT(expected_changed == changed);
5245 }
5246#endif
5247};
5248
5249
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005250struct ToLowerTraits {
5251 typedef unibrow::ToLowercase UnibrowConverter;
5252
lrn@chromium.org303ada72010-10-27 09:33:13 +00005253 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005254};
5255
5256
5257struct ToUpperTraits {
5258 typedef unibrow::ToUppercase UnibrowConverter;
5259
lrn@chromium.org303ada72010-10-27 09:33:13 +00005260 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005261};
5262
5263} // namespace
5264
5265
5266template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005267MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005268 Arguments args,
5269 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005270 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005271 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005272 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005273
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005274 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005275 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005276 if (length == 0) return s;
5277
5278 // Simpler handling of ascii strings.
5279 //
5280 // NOTE: This assumes that the upper/lower case of an ascii
5281 // character is also ascii. This is currently the case, but it
5282 // might break in the future if we implement more context and locale
5283 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005284 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005285 Object* o;
5286 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5287 if (!maybe_o->ToObject(&o)) return maybe_o;
5288 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005289 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005290 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005291 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005292 return has_changed_character ? result : s;
5293 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005294
lrn@chromium.org303ada72010-10-27 09:33:13 +00005295 Object* answer;
5296 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5297 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5298 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005299 if (answer->IsSmi()) {
5300 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005301 { MaybeObject* maybe_answer =
5302 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5303 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5304 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005305 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005306 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005307}
5308
5309
lrn@chromium.org303ada72010-10-27 09:33:13 +00005310static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005311 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005312}
5313
5314
lrn@chromium.org303ada72010-10-27 09:33:13 +00005315static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005316 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005317}
5318
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005319
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005320static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5321 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5322}
5323
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005324
lrn@chromium.org303ada72010-10-27 09:33:13 +00005325static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005326 NoHandleAllocation ha;
5327 ASSERT(args.length() == 3);
5328
5329 CONVERT_CHECKED(String, s, args[0]);
5330 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5331 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5332
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005333 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005334 int length = s->length();
5335
5336 int left = 0;
5337 if (trimLeft) {
5338 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5339 left++;
5340 }
5341 }
5342
5343 int right = length;
5344 if (trimRight) {
5345 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5346 right--;
5347 }
5348 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005349 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005350}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005351
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005352
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005353template <typename SubjectChar, typename PatternChar>
5354void FindStringIndices(Vector<const SubjectChar> subject,
5355 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005356 ZoneList<int>* indices,
5357 unsigned int limit) {
5358 ASSERT(limit > 0);
5359 // Collect indices of pattern in subject, and the end-of-string index.
5360 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005361 StringSearch<PatternChar, SubjectChar> search(pattern);
5362 int pattern_length = pattern.length();
5363 int index = 0;
5364 while (limit > 0) {
5365 index = search.Search(subject, index);
5366 if (index < 0) return;
5367 indices->Add(index);
5368 index += pattern_length;
5369 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005370 }
5371}
5372
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005373
lrn@chromium.org303ada72010-10-27 09:33:13 +00005374static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005375 ASSERT(args.length() == 3);
5376 HandleScope handle_scope;
5377 CONVERT_ARG_CHECKED(String, subject, 0);
5378 CONVERT_ARG_CHECKED(String, pattern, 1);
5379 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5380
5381 int subject_length = subject->length();
5382 int pattern_length = pattern->length();
5383 RUNTIME_ASSERT(pattern_length > 0);
5384
5385 // The limit can be very large (0xffffffffu), but since the pattern
5386 // isn't empty, we can never create more parts than ~half the length
5387 // of the subject.
5388
5389 if (!subject->IsFlat()) FlattenString(subject);
5390
5391 static const int kMaxInitialListCapacity = 16;
5392
5393 ZoneScope scope(DELETE_ON_EXIT);
5394
5395 // Find (up to limit) indices of separator and end-of-string in subject
5396 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5397 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005398 if (!pattern->IsFlat()) FlattenString(pattern);
5399
5400 // No allocation block.
5401 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005402 AssertNoAllocation nogc;
5403 if (subject->IsAsciiRepresentation()) {
5404 Vector<const char> subject_vector = subject->ToAsciiVector();
5405 if (pattern->IsAsciiRepresentation()) {
5406 FindStringIndices(subject_vector,
5407 pattern->ToAsciiVector(),
5408 &indices,
5409 limit);
5410 } else {
5411 FindStringIndices(subject_vector,
5412 pattern->ToUC16Vector(),
5413 &indices,
5414 limit);
5415 }
5416 } else {
5417 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5418 if (pattern->IsAsciiRepresentation()) {
5419 FindStringIndices(subject_vector,
5420 pattern->ToAsciiVector(),
5421 &indices,
5422 limit);
5423 } else {
5424 FindStringIndices(subject_vector,
5425 pattern->ToUC16Vector(),
5426 &indices,
5427 limit);
5428 }
5429 }
5430 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005431
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005432 if (static_cast<uint32_t>(indices.length()) < limit) {
5433 indices.Add(subject_length);
5434 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005435
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005436 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005437
5438 // Create JSArray of substrings separated by separator.
5439 int part_count = indices.length();
5440
5441 Handle<JSArray> result = Factory::NewJSArray(part_count);
5442 result->set_length(Smi::FromInt(part_count));
5443
5444 ASSERT(result->HasFastElements());
5445
5446 if (part_count == 1 && indices.at(0) == subject_length) {
5447 FixedArray::cast(result->elements())->set(0, *subject);
5448 return *result;
5449 }
5450
5451 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5452 int part_start = 0;
5453 for (int i = 0; i < part_count; i++) {
5454 HandleScope local_loop_handle;
5455 int part_end = indices.at(i);
5456 Handle<String> substring =
5457 Factory::NewSubString(subject, part_start, part_end);
5458 elements->set(i, *substring);
5459 part_start = part_end + pattern_length;
5460 }
5461
5462 return *result;
5463}
5464
5465
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005466// Copies ascii characters to the given fixed array looking up
5467// one-char strings in the cache. Gives up on the first char that is
5468// not in the cache and fills the remainder with smi zeros. Returns
5469// the length of the successfully copied prefix.
5470static int CopyCachedAsciiCharsToArray(const char* chars,
5471 FixedArray* elements,
5472 int length) {
5473 AssertNoAllocation nogc;
5474 FixedArray* ascii_cache = Heap::single_character_string_cache();
5475 Object* undefined = Heap::undefined_value();
5476 int i;
5477 for (i = 0; i < length; ++i) {
5478 Object* value = ascii_cache->get(chars[i]);
5479 if (value == undefined) break;
5480 ASSERT(!Heap::InNewSpace(value));
5481 elements->set(i, value, SKIP_WRITE_BARRIER);
5482 }
5483 if (i < length) {
5484 ASSERT(Smi::FromInt(0) == 0);
5485 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5486 }
5487#ifdef DEBUG
5488 for (int j = 0; j < length; ++j) {
5489 Object* element = elements->get(j);
5490 ASSERT(element == Smi::FromInt(0) ||
5491 (element->IsString() && String::cast(element)->LooksValid()));
5492 }
5493#endif
5494 return i;
5495}
5496
5497
5498// Converts a String to JSArray.
5499// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005500static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005501 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005502 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005503 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005504 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005505
5506 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005507 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005508
5509 Handle<FixedArray> elements;
5510 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005511 Object* obj;
5512 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5513 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5514 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005515 elements = Handle<FixedArray>(FixedArray::cast(obj));
5516
5517 Vector<const char> chars = s->ToAsciiVector();
5518 // Note, this will initialize all elements (not only the prefix)
5519 // to prevent GC from seeing partially initialized array.
5520 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5521 *elements,
5522 length);
5523
5524 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005525 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5526 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005527 }
5528 } else {
5529 elements = Factory::NewFixedArray(length);
5530 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005531 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5532 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005533 }
5534 }
5535
5536#ifdef DEBUG
5537 for (int i = 0; i < length; ++i) {
5538 ASSERT(String::cast(elements->get(i))->length() == 1);
5539 }
5540#endif
5541
5542 return *Factory::NewJSArrayWithElements(elements);
5543}
5544
5545
lrn@chromium.org303ada72010-10-27 09:33:13 +00005546static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005547 NoHandleAllocation ha;
5548 ASSERT(args.length() == 1);
5549 CONVERT_CHECKED(String, value, args[0]);
5550 return value->ToObject();
5551}
5552
5553
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005554bool Runtime::IsUpperCaseChar(uint16_t ch) {
5555 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5556 int char_length = to_upper_mapping.get(ch, 0, chars);
5557 return char_length == 0;
5558}
5559
5560
lrn@chromium.org303ada72010-10-27 09:33:13 +00005561static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005562 NoHandleAllocation ha;
5563 ASSERT(args.length() == 1);
5564
5565 Object* number = args[0];
5566 RUNTIME_ASSERT(number->IsNumber());
5567
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005568 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005569}
5570
5571
lrn@chromium.org303ada72010-10-27 09:33:13 +00005572static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005573 NoHandleAllocation ha;
5574 ASSERT(args.length() == 1);
5575
5576 Object* number = args[0];
5577 RUNTIME_ASSERT(number->IsNumber());
5578
5579 return Heap::NumberToString(number, false);
5580}
5581
5582
lrn@chromium.org303ada72010-10-27 09:33:13 +00005583static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005584 NoHandleAllocation ha;
5585 ASSERT(args.length() == 1);
5586
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005587 CONVERT_DOUBLE_CHECKED(number, args[0]);
5588
5589 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5590 if (number > 0 && number <= Smi::kMaxValue) {
5591 return Smi::FromInt(static_cast<int>(number));
5592 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005593 return Heap::NumberFromDouble(DoubleToInteger(number));
5594}
5595
5596
lrn@chromium.org303ada72010-10-27 09:33:13 +00005597static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005598 NoHandleAllocation ha;
5599 ASSERT(args.length() == 1);
5600
5601 CONVERT_DOUBLE_CHECKED(number, args[0]);
5602
5603 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5604 if (number > 0 && number <= Smi::kMaxValue) {
5605 return Smi::FromInt(static_cast<int>(number));
5606 }
5607
5608 double double_value = DoubleToInteger(number);
5609 // Map both -0 and +0 to +0.
5610 if (double_value == 0) double_value = 0;
5611
5612 return Heap::NumberFromDouble(double_value);
5613}
5614
5615
lrn@chromium.org303ada72010-10-27 09:33:13 +00005616static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005617 NoHandleAllocation ha;
5618 ASSERT(args.length() == 1);
5619
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005620 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005621 return Heap::NumberFromUint32(number);
5622}
5623
5624
lrn@chromium.org303ada72010-10-27 09:33:13 +00005625static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005626 NoHandleAllocation ha;
5627 ASSERT(args.length() == 1);
5628
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005629 CONVERT_DOUBLE_CHECKED(number, args[0]);
5630
5631 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5632 if (number > 0 && number <= Smi::kMaxValue) {
5633 return Smi::FromInt(static_cast<int>(number));
5634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005635 return Heap::NumberFromInt32(DoubleToInt32(number));
5636}
5637
5638
ager@chromium.org870a0b62008-11-04 11:43:05 +00005639// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5640// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005641static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005642 NoHandleAllocation ha;
5643 ASSERT(args.length() == 1);
5644
5645 Object* obj = args[0];
5646 if (obj->IsSmi()) {
5647 return obj;
5648 }
5649 if (obj->IsHeapNumber()) {
5650 double value = HeapNumber::cast(obj)->value();
5651 int int_value = FastD2I(value);
5652 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5653 return Smi::FromInt(int_value);
5654 }
5655 }
5656 return Heap::nan_value();
5657}
5658
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005659
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005660static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5661 NoHandleAllocation ha;
5662 ASSERT(args.length() == 0);
5663 return Heap::AllocateHeapNumber(0);
5664}
5665
5666
lrn@chromium.org303ada72010-10-27 09:33:13 +00005667static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005668 NoHandleAllocation ha;
5669 ASSERT(args.length() == 2);
5670
5671 CONVERT_DOUBLE_CHECKED(x, args[0]);
5672 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005673 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005674}
5675
5676
lrn@chromium.org303ada72010-10-27 09:33:13 +00005677static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005678 NoHandleAllocation ha;
5679 ASSERT(args.length() == 2);
5680
5681 CONVERT_DOUBLE_CHECKED(x, args[0]);
5682 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005683 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005684}
5685
5686
lrn@chromium.org303ada72010-10-27 09:33:13 +00005687static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005688 NoHandleAllocation ha;
5689 ASSERT(args.length() == 2);
5690
5691 CONVERT_DOUBLE_CHECKED(x, args[0]);
5692 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005693 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005694}
5695
5696
lrn@chromium.org303ada72010-10-27 09:33:13 +00005697static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005698 NoHandleAllocation ha;
5699 ASSERT(args.length() == 1);
5700
5701 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005702 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005703}
5704
5705
lrn@chromium.org303ada72010-10-27 09:33:13 +00005706static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005707 NoHandleAllocation ha;
5708 ASSERT(args.length() == 0);
5709
5710 return Heap::NumberFromDouble(9876543210.0);
5711}
5712
5713
lrn@chromium.org303ada72010-10-27 09:33:13 +00005714static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005715 NoHandleAllocation ha;
5716 ASSERT(args.length() == 2);
5717
5718 CONVERT_DOUBLE_CHECKED(x, args[0]);
5719 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005720 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005721}
5722
5723
lrn@chromium.org303ada72010-10-27 09:33:13 +00005724static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005725 NoHandleAllocation ha;
5726 ASSERT(args.length() == 2);
5727
5728 CONVERT_DOUBLE_CHECKED(x, args[0]);
5729 CONVERT_DOUBLE_CHECKED(y, args[1]);
5730
ager@chromium.org3811b432009-10-28 14:53:37 +00005731 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005732 // NumberFromDouble may return a Smi instead of a Number object
5733 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005734}
5735
5736
lrn@chromium.org303ada72010-10-27 09:33:13 +00005737static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005738 NoHandleAllocation ha;
5739 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005740 CONVERT_CHECKED(String, str1, args[0]);
5741 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005742 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005743 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005744}
5745
5746
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005747template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005748static inline void StringBuilderConcatHelper(String* special,
5749 sinkchar* sink,
5750 FixedArray* fixed_array,
5751 int array_length) {
5752 int position = 0;
5753 for (int i = 0; i < array_length; i++) {
5754 Object* element = fixed_array->get(i);
5755 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005756 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005757 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005758 int pos;
5759 int len;
5760 if (encoded_slice > 0) {
5761 // Position and length encoded in one smi.
5762 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5763 len = StringBuilderSubstringLength::decode(encoded_slice);
5764 } else {
5765 // Position and length encoded in two smis.
5766 Object* obj = fixed_array->get(++i);
5767 ASSERT(obj->IsSmi());
5768 pos = Smi::cast(obj)->value();
5769 len = -encoded_slice;
5770 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005771 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005772 sink + position,
5773 pos,
5774 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005775 position += len;
5776 } else {
5777 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005778 int element_length = string->length();
5779 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005780 position += element_length;
5781 }
5782 }
5783}
5784
5785
lrn@chromium.org303ada72010-10-27 09:33:13 +00005786static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005787 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005788 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005789 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005790 if (!args[1]->IsSmi()) {
5791 Top::context()->mark_out_of_memory();
5792 return Failure::OutOfMemoryException();
5793 }
5794 int array_length = Smi::cast(args[1])->value();
5795 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005796
5797 // This assumption is used by the slice encoding in one or two smis.
5798 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5799
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005800 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005801 if (!array->HasFastElements()) {
5802 return Top::Throw(Heap::illegal_argument_symbol());
5803 }
5804 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005805 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005806 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005808
5809 if (array_length == 0) {
5810 return Heap::empty_string();
5811 } else if (array_length == 1) {
5812 Object* first = fixed_array->get(0);
5813 if (first->IsString()) return first;
5814 }
5815
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005816 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005817 int position = 0;
5818 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005819 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005820 Object* elt = fixed_array->get(i);
5821 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005822 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005823 int smi_value = Smi::cast(elt)->value();
5824 int pos;
5825 int len;
5826 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005827 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005828 pos = StringBuilderSubstringPosition::decode(smi_value);
5829 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005830 } else {
5831 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005832 len = -smi_value;
5833 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005834 i++;
5835 if (i >= array_length) {
5836 return Top::Throw(Heap::illegal_argument_symbol());
5837 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005838 Object* next_smi = fixed_array->get(i);
5839 if (!next_smi->IsSmi()) {
5840 return Top::Throw(Heap::illegal_argument_symbol());
5841 }
5842 pos = Smi::cast(next_smi)->value();
5843 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005844 return Top::Throw(Heap::illegal_argument_symbol());
5845 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005846 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005847 ASSERT(pos >= 0);
5848 ASSERT(len >= 0);
5849 if (pos > special_length || len > special_length - pos) {
5850 return Top::Throw(Heap::illegal_argument_symbol());
5851 }
5852 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005853 } else if (elt->IsString()) {
5854 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005855 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005856 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005857 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005858 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005859 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005860 } else {
5861 return Top::Throw(Heap::illegal_argument_symbol());
5862 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005863 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005864 Top::context()->mark_out_of_memory();
5865 return Failure::OutOfMemoryException();
5866 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005867 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005868 }
5869
5870 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005871 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005872
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005873 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005874 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5875 if (!maybe_object->ToObject(&object)) return maybe_object;
5876 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005877 SeqAsciiString* answer = SeqAsciiString::cast(object);
5878 StringBuilderConcatHelper(special,
5879 answer->GetChars(),
5880 fixed_array,
5881 array_length);
5882 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005883 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005884 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5885 if (!maybe_object->ToObject(&object)) return maybe_object;
5886 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005887 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5888 StringBuilderConcatHelper(special,
5889 answer->GetChars(),
5890 fixed_array,
5891 array_length);
5892 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005893 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005894}
5895
5896
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005897static MaybeObject* Runtime_StringBuilderJoin(Arguments args) {
5898 NoHandleAllocation ha;
5899 ASSERT(args.length() == 3);
5900 CONVERT_CHECKED(JSArray, array, args[0]);
5901 if (!args[1]->IsSmi()) {
5902 Top::context()->mark_out_of_memory();
5903 return Failure::OutOfMemoryException();
5904 }
5905 int array_length = Smi::cast(args[1])->value();
5906 CONVERT_CHECKED(String, separator, args[2]);
5907
5908 if (!array->HasFastElements()) {
5909 return Top::Throw(Heap::illegal_argument_symbol());
5910 }
5911 FixedArray* fixed_array = FixedArray::cast(array->elements());
5912 if (fixed_array->length() < array_length) {
5913 array_length = fixed_array->length();
5914 }
5915
5916 if (array_length == 0) {
5917 return Heap::empty_string();
5918 } else if (array_length == 1) {
5919 Object* first = fixed_array->get(0);
5920 if (first->IsString()) return first;
5921 }
5922
5923 int separator_length = separator->length();
5924 int max_nof_separators =
5925 (String::kMaxLength + separator_length - 1) / separator_length;
5926 if (max_nof_separators < (array_length - 1)) {
5927 Top::context()->mark_out_of_memory();
5928 return Failure::OutOfMemoryException();
5929 }
5930 int length = (array_length - 1) * separator_length;
5931 for (int i = 0; i < array_length; i++) {
5932 Object* element_obj = fixed_array->get(i);
5933 if (!element_obj->IsString()) {
5934 // TODO(1161): handle this case.
5935 return Top::Throw(Heap::illegal_argument_symbol());
5936 }
5937 String* element = String::cast(element_obj);
5938 int increment = element->length();
5939 if (increment > String::kMaxLength - length) {
5940 Top::context()->mark_out_of_memory();
5941 return Failure::OutOfMemoryException();
5942 }
5943 length += increment;
5944 }
5945
5946 Object* object;
5947 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5948 if (!maybe_object->ToObject(&object)) return maybe_object;
5949 }
5950 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5951
5952 uc16* sink = answer->GetChars();
5953#ifdef DEBUG
5954 uc16* end = sink + length;
5955#endif
5956
5957 String* first = String::cast(fixed_array->get(0));
5958 int first_length = first->length();
5959 String::WriteToFlat(first, sink, 0, first_length);
5960 sink += first_length;
5961
5962 for (int i = 1; i < array_length; i++) {
5963 ASSERT(sink + separator_length <= end);
5964 String::WriteToFlat(separator, sink, 0, separator_length);
5965 sink += separator_length;
5966
5967 String* element = String::cast(fixed_array->get(i));
5968 int element_length = element->length();
5969 ASSERT(sink + element_length <= end);
5970 String::WriteToFlat(element, sink, 0, element_length);
5971 sink += element_length;
5972 }
5973 ASSERT(sink == end);
5974
5975 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
5976 return answer;
5977}
5978
5979
lrn@chromium.org303ada72010-10-27 09:33:13 +00005980static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 NoHandleAllocation ha;
5982 ASSERT(args.length() == 2);
5983
5984 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5985 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5986 return Heap::NumberFromInt32(x | y);
5987}
5988
5989
lrn@chromium.org303ada72010-10-27 09:33:13 +00005990static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005991 NoHandleAllocation ha;
5992 ASSERT(args.length() == 2);
5993
5994 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5995 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5996 return Heap::NumberFromInt32(x & y);
5997}
5998
5999
lrn@chromium.org303ada72010-10-27 09:33:13 +00006000static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001 NoHandleAllocation ha;
6002 ASSERT(args.length() == 2);
6003
6004 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6005 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6006 return Heap::NumberFromInt32(x ^ y);
6007}
6008
6009
lrn@chromium.org303ada72010-10-27 09:33:13 +00006010static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006011 NoHandleAllocation ha;
6012 ASSERT(args.length() == 1);
6013
6014 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6015 return Heap::NumberFromInt32(~x);
6016}
6017
6018
lrn@chromium.org303ada72010-10-27 09:33:13 +00006019static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020 NoHandleAllocation ha;
6021 ASSERT(args.length() == 2);
6022
6023 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6024 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6025 return Heap::NumberFromInt32(x << (y & 0x1f));
6026}
6027
6028
lrn@chromium.org303ada72010-10-27 09:33:13 +00006029static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030 NoHandleAllocation ha;
6031 ASSERT(args.length() == 2);
6032
6033 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6034 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6035 return Heap::NumberFromUint32(x >> (y & 0x1f));
6036}
6037
6038
lrn@chromium.org303ada72010-10-27 09:33:13 +00006039static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 NoHandleAllocation ha;
6041 ASSERT(args.length() == 2);
6042
6043 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6044 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6045 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
6046}
6047
6048
lrn@chromium.org303ada72010-10-27 09:33:13 +00006049static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006050 NoHandleAllocation ha;
6051 ASSERT(args.length() == 2);
6052
6053 CONVERT_DOUBLE_CHECKED(x, args[0]);
6054 CONVERT_DOUBLE_CHECKED(y, args[1]);
6055 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6056 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6057 if (x == y) return Smi::FromInt(EQUAL);
6058 Object* result;
6059 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6060 result = Smi::FromInt(EQUAL);
6061 } else {
6062 result = Smi::FromInt(NOT_EQUAL);
6063 }
6064 return result;
6065}
6066
6067
lrn@chromium.org303ada72010-10-27 09:33:13 +00006068static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006069 NoHandleAllocation ha;
6070 ASSERT(args.length() == 2);
6071
6072 CONVERT_CHECKED(String, x, args[0]);
6073 CONVERT_CHECKED(String, y, args[1]);
6074
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006075 bool not_equal = !x->Equals(y);
6076 // This is slightly convoluted because the value that signifies
6077 // equality is 0 and inequality is 1 so we have to negate the result
6078 // from String::Equals.
6079 ASSERT(not_equal == 0 || not_equal == 1);
6080 STATIC_CHECK(EQUAL == 0);
6081 STATIC_CHECK(NOT_EQUAL == 1);
6082 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006083}
6084
6085
lrn@chromium.org303ada72010-10-27 09:33:13 +00006086static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006087 NoHandleAllocation ha;
6088 ASSERT(args.length() == 3);
6089
6090 CONVERT_DOUBLE_CHECKED(x, args[0]);
6091 CONVERT_DOUBLE_CHECKED(y, args[1]);
6092 if (isnan(x) || isnan(y)) return args[2];
6093 if (x == y) return Smi::FromInt(EQUAL);
6094 if (isless(x, y)) return Smi::FromInt(LESS);
6095 return Smi::FromInt(GREATER);
6096}
6097
6098
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006099// Compare two Smis as if they were converted to strings and then
6100// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006101static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006102 NoHandleAllocation ha;
6103 ASSERT(args.length() == 2);
6104
6105 // Arrays for the individual characters of the two Smis. Smis are
6106 // 31 bit integers and 10 decimal digits are therefore enough.
6107 static int x_elms[10];
6108 static int y_elms[10];
6109
6110 // Extract the integer values from the Smis.
6111 CONVERT_CHECKED(Smi, x, args[0]);
6112 CONVERT_CHECKED(Smi, y, args[1]);
6113 int x_value = x->value();
6114 int y_value = y->value();
6115
6116 // If the integers are equal so are the string representations.
6117 if (x_value == y_value) return Smi::FromInt(EQUAL);
6118
6119 // If one of the integers are zero the normal integer order is the
6120 // same as the lexicographic order of the string representations.
6121 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6122
ager@chromium.org32912102009-01-16 10:38:43 +00006123 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006124 // smallest because the char code of '-' is less than the char code
6125 // of any digit. Otherwise, we make both values positive.
6126 if (x_value < 0 || y_value < 0) {
6127 if (y_value >= 0) return Smi::FromInt(LESS);
6128 if (x_value >= 0) return Smi::FromInt(GREATER);
6129 x_value = -x_value;
6130 y_value = -y_value;
6131 }
6132
6133 // Convert the integers to arrays of their decimal digits.
6134 int x_index = 0;
6135 int y_index = 0;
6136 while (x_value > 0) {
6137 x_elms[x_index++] = x_value % 10;
6138 x_value /= 10;
6139 }
6140 while (y_value > 0) {
6141 y_elms[y_index++] = y_value % 10;
6142 y_value /= 10;
6143 }
6144
6145 // Loop through the arrays of decimal digits finding the first place
6146 // where they differ.
6147 while (--x_index >= 0 && --y_index >= 0) {
6148 int diff = x_elms[x_index] - y_elms[y_index];
6149 if (diff != 0) return Smi::FromInt(diff);
6150 }
6151
6152 // If one array is a suffix of the other array, the longest array is
6153 // the representation of the largest of the Smis in the
6154 // lexicographic ordering.
6155 return Smi::FromInt(x_index - y_index);
6156}
6157
6158
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006159static Object* StringInputBufferCompare(String* x, String* y) {
6160 static StringInputBuffer bufx;
6161 static StringInputBuffer bufy;
6162 bufx.Reset(x);
6163 bufy.Reset(y);
6164 while (bufx.has_more() && bufy.has_more()) {
6165 int d = bufx.GetNext() - bufy.GetNext();
6166 if (d < 0) return Smi::FromInt(LESS);
6167 else if (d > 0) return Smi::FromInt(GREATER);
6168 }
6169
6170 // x is (non-trivial) prefix of y:
6171 if (bufy.has_more()) return Smi::FromInt(LESS);
6172 // y is prefix of x:
6173 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6174}
6175
6176
6177static Object* FlatStringCompare(String* x, String* y) {
6178 ASSERT(x->IsFlat());
6179 ASSERT(y->IsFlat());
6180 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6181 int prefix_length = x->length();
6182 if (y->length() < prefix_length) {
6183 prefix_length = y->length();
6184 equal_prefix_result = Smi::FromInt(GREATER);
6185 } else if (y->length() > prefix_length) {
6186 equal_prefix_result = Smi::FromInt(LESS);
6187 }
6188 int r;
6189 if (x->IsAsciiRepresentation()) {
6190 Vector<const char> x_chars = x->ToAsciiVector();
6191 if (y->IsAsciiRepresentation()) {
6192 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006193 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006194 } else {
6195 Vector<const uc16> y_chars = y->ToUC16Vector();
6196 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6197 }
6198 } else {
6199 Vector<const uc16> x_chars = x->ToUC16Vector();
6200 if (y->IsAsciiRepresentation()) {
6201 Vector<const char> y_chars = y->ToAsciiVector();
6202 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6203 } else {
6204 Vector<const uc16> y_chars = y->ToUC16Vector();
6205 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6206 }
6207 }
6208 Object* result;
6209 if (r == 0) {
6210 result = equal_prefix_result;
6211 } else {
6212 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6213 }
6214 ASSERT(result == StringInputBufferCompare(x, y));
6215 return result;
6216}
6217
6218
lrn@chromium.org303ada72010-10-27 09:33:13 +00006219static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220 NoHandleAllocation ha;
6221 ASSERT(args.length() == 2);
6222
6223 CONVERT_CHECKED(String, x, args[0]);
6224 CONVERT_CHECKED(String, y, args[1]);
6225
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006226 Counters::string_compare_runtime.Increment();
6227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006228 // A few fast case tests before we flatten.
6229 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006230 if (y->length() == 0) {
6231 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006232 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006233 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006234 return Smi::FromInt(LESS);
6235 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006236
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006237 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006238 if (d < 0) return Smi::FromInt(LESS);
6239 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006240
lrn@chromium.org303ada72010-10-27 09:33:13 +00006241 Object* obj;
6242 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
6243 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6244 }
6245 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
6246 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6247 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006248
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006249 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
6250 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006251}
6252
6253
lrn@chromium.org303ada72010-10-27 09:33:13 +00006254static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006255 NoHandleAllocation ha;
6256 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006257 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006258
6259 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006260 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006261}
6262
6263
lrn@chromium.org303ada72010-10-27 09:33:13 +00006264static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006265 NoHandleAllocation ha;
6266 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006267 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006268
6269 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006270 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006271}
6272
6273
lrn@chromium.org303ada72010-10-27 09:33:13 +00006274static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006275 NoHandleAllocation ha;
6276 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006277 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006278
6279 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006280 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006281}
6282
6283
lrn@chromium.org303ada72010-10-27 09:33:13 +00006284static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006285 NoHandleAllocation ha;
6286 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006287 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006288
6289 CONVERT_DOUBLE_CHECKED(x, args[0]);
6290 CONVERT_DOUBLE_CHECKED(y, args[1]);
6291 double result;
6292 if (isinf(x) && isinf(y)) {
6293 // Make sure that the result in case of two infinite arguments
6294 // is a multiple of Pi / 4. The sign of the result is determined
6295 // by the first argument (x) and the sign of the second argument
6296 // determines the multiplier: one or three.
6297 static double kPiDividedBy4 = 0.78539816339744830962;
6298 int multiplier = (x < 0) ? -1 : 1;
6299 if (y < 0) multiplier *= 3;
6300 result = multiplier * kPiDividedBy4;
6301 } else {
6302 result = atan2(x, y);
6303 }
6304 return Heap::AllocateHeapNumber(result);
6305}
6306
6307
lrn@chromium.org303ada72010-10-27 09:33:13 +00006308static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006309 NoHandleAllocation ha;
6310 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006311 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006312
6313 CONVERT_DOUBLE_CHECKED(x, args[0]);
6314 return Heap::NumberFromDouble(ceiling(x));
6315}
6316
6317
lrn@chromium.org303ada72010-10-27 09:33:13 +00006318static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006319 NoHandleAllocation ha;
6320 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006321 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006322
6323 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006324 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006325}
6326
6327
lrn@chromium.org303ada72010-10-27 09:33:13 +00006328static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006329 NoHandleAllocation ha;
6330 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006331 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006332
6333 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006334 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006335}
6336
6337
lrn@chromium.org303ada72010-10-27 09:33:13 +00006338static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006339 NoHandleAllocation ha;
6340 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006341 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006342
6343 CONVERT_DOUBLE_CHECKED(x, args[0]);
6344 return Heap::NumberFromDouble(floor(x));
6345}
6346
6347
lrn@chromium.org303ada72010-10-27 09:33:13 +00006348static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006349 NoHandleAllocation ha;
6350 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006351 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006352
6353 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006354 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006355}
6356
6357
lrn@chromium.org303ada72010-10-27 09:33:13 +00006358static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006359 NoHandleAllocation ha;
6360 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006361 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006362
6363 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006364
6365 // If the second argument is a smi, it is much faster to call the
6366 // custom powi() function than the generic pow().
6367 if (args[1]->IsSmi()) {
6368 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006369 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006370 }
6371
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006372 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006373 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006374}
6375
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006376// Fast version of Math.pow if we know that y is not an integer and
6377// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006378static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006379 NoHandleAllocation ha;
6380 ASSERT(args.length() == 2);
6381 CONVERT_DOUBLE_CHECKED(x, args[0]);
6382 CONVERT_DOUBLE_CHECKED(y, args[1]);
6383 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006384 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006385 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006386 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006387 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006388 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006389 }
6390}
6391
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006392
lrn@chromium.org303ada72010-10-27 09:33:13 +00006393static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006394 NoHandleAllocation ha;
6395 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006396 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006397
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006398 if (!args[0]->IsHeapNumber()) {
6399 // Must be smi. Return the argument unchanged for all the other types
6400 // to make fuzz-natives test happy.
6401 return args[0];
6402 }
6403
6404 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6405
6406 double value = number->value();
6407 int exponent = number->get_exponent();
6408 int sign = number->get_sign();
6409
6410 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6411 // should be rounded to 2^30, which is not smi.
6412 if (!sign && exponent <= kSmiValueSize - 3) {
6413 return Smi::FromInt(static_cast<int>(value + 0.5));
6414 }
6415
6416 // If the magnitude is big enough, there's no place for fraction part. If we
6417 // try to add 0.5 to this number, 1.0 will be added instead.
6418 if (exponent >= 52) {
6419 return number;
6420 }
6421
6422 if (sign && value >= -0.5) return Heap::minus_zero_value();
6423
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006424 // Do not call NumberFromDouble() to avoid extra checks.
6425 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006426}
6427
6428
lrn@chromium.org303ada72010-10-27 09:33:13 +00006429static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006430 NoHandleAllocation ha;
6431 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006432 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006433
6434 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006435 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006436}
6437
6438
lrn@chromium.org303ada72010-10-27 09:33:13 +00006439static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006440 NoHandleAllocation ha;
6441 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006442 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006443
6444 CONVERT_DOUBLE_CHECKED(x, args[0]);
6445 return Heap::AllocateHeapNumber(sqrt(x));
6446}
6447
6448
lrn@chromium.org303ada72010-10-27 09:33:13 +00006449static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006450 NoHandleAllocation ha;
6451 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006452 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453
6454 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006455 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006456}
6457
6458
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006459static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006460 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6461 181, 212, 243, 273, 304, 334};
6462 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6463 182, 213, 244, 274, 305, 335};
6464
6465 year += month / 12;
6466 month %= 12;
6467 if (month < 0) {
6468 year--;
6469 month += 12;
6470 }
6471
6472 ASSERT(month >= 0);
6473 ASSERT(month < 12);
6474
6475 // year_delta is an arbitrary number such that:
6476 // a) year_delta = -1 (mod 400)
6477 // b) year + year_delta > 0 for years in the range defined by
6478 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6479 // Jan 1 1970. This is required so that we don't run into integer
6480 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006481 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006482 // operations.
6483 static const int year_delta = 399999;
6484 static const int base_day = 365 * (1970 + year_delta) +
6485 (1970 + year_delta) / 4 -
6486 (1970 + year_delta) / 100 +
6487 (1970 + year_delta) / 400;
6488
6489 int year1 = year + year_delta;
6490 int day_from_year = 365 * year1 +
6491 year1 / 4 -
6492 year1 / 100 +
6493 year1 / 400 -
6494 base_day;
6495
6496 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006497 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006498 }
6499
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006500 return day_from_year + day_from_month_leap[month] + day - 1;
6501}
6502
6503
lrn@chromium.org303ada72010-10-27 09:33:13 +00006504static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006505 NoHandleAllocation ha;
6506 ASSERT(args.length() == 3);
6507
6508 CONVERT_SMI_CHECKED(year, args[0]);
6509 CONVERT_SMI_CHECKED(month, args[1]);
6510 CONVERT_SMI_CHECKED(date, args[2]);
6511
6512 return Smi::FromInt(MakeDay(year, month, date));
6513}
6514
6515
6516static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6517static const int kDaysIn4Years = 4 * 365 + 1;
6518static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6519static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6520static const int kDays1970to2000 = 30 * 365 + 7;
6521static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6522 kDays1970to2000;
6523static const int kYearsOffset = 400000;
6524
6525static const char kDayInYear[] = {
6526 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6527 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6528 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6529 22, 23, 24, 25, 26, 27, 28,
6530 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6531 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6532 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6533 22, 23, 24, 25, 26, 27, 28, 29, 30,
6534 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6535 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6536 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6537 22, 23, 24, 25, 26, 27, 28, 29, 30,
6538 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6539 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6540 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6541 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6542 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6543 22, 23, 24, 25, 26, 27, 28, 29, 30,
6544 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6545 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6546 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6547 22, 23, 24, 25, 26, 27, 28, 29, 30,
6548 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6549 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6550
6551 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6552 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6553 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6554 22, 23, 24, 25, 26, 27, 28,
6555 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6556 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6557 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6558 22, 23, 24, 25, 26, 27, 28, 29, 30,
6559 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6560 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6561 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6562 22, 23, 24, 25, 26, 27, 28, 29, 30,
6563 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6564 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6565 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6566 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6567 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6568 22, 23, 24, 25, 26, 27, 28, 29, 30,
6569 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6570 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6571 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6572 22, 23, 24, 25, 26, 27, 28, 29, 30,
6573 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6574 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6575
6576 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6577 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6578 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6579 22, 23, 24, 25, 26, 27, 28, 29,
6580 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6581 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6582 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6583 22, 23, 24, 25, 26, 27, 28, 29, 30,
6584 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6585 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6586 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6587 22, 23, 24, 25, 26, 27, 28, 29, 30,
6588 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6589 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6590 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6591 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6592 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6593 22, 23, 24, 25, 26, 27, 28, 29, 30,
6594 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6595 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6596 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6597 22, 23, 24, 25, 26, 27, 28, 29, 30,
6598 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6599 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6600
6601 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6602 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6603 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6604 22, 23, 24, 25, 26, 27, 28,
6605 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6606 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6607 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6608 22, 23, 24, 25, 26, 27, 28, 29, 30,
6609 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6610 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6611 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6612 22, 23, 24, 25, 26, 27, 28, 29, 30,
6613 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6614 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6615 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6616 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6617 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6618 22, 23, 24, 25, 26, 27, 28, 29, 30,
6619 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6620 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6621 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6622 22, 23, 24, 25, 26, 27, 28, 29, 30,
6623 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6624 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6625
6626static const char kMonthInYear[] = {
6627 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6628 0, 0, 0, 0, 0, 0,
6629 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6630 1, 1, 1,
6631 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6632 2, 2, 2, 2, 2, 2,
6633 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6634 3, 3, 3, 3, 3,
6635 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6636 4, 4, 4, 4, 4, 4,
6637 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6638 5, 5, 5, 5, 5,
6639 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6640 6, 6, 6, 6, 6, 6,
6641 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6642 7, 7, 7, 7, 7, 7,
6643 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6644 8, 8, 8, 8, 8,
6645 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6646 9, 9, 9, 9, 9, 9,
6647 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6648 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6649 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6650 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6651
6652 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6653 0, 0, 0, 0, 0, 0,
6654 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6655 1, 1, 1,
6656 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6657 2, 2, 2, 2, 2, 2,
6658 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6659 3, 3, 3, 3, 3,
6660 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6661 4, 4, 4, 4, 4, 4,
6662 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6663 5, 5, 5, 5, 5,
6664 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6665 6, 6, 6, 6, 6, 6,
6666 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6667 7, 7, 7, 7, 7, 7,
6668 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6669 8, 8, 8, 8, 8,
6670 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6671 9, 9, 9, 9, 9, 9,
6672 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6673 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6674 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6675 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6676
6677 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6678 0, 0, 0, 0, 0, 0,
6679 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6680 1, 1, 1, 1,
6681 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6682 2, 2, 2, 2, 2, 2,
6683 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6684 3, 3, 3, 3, 3,
6685 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6686 4, 4, 4, 4, 4, 4,
6687 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6688 5, 5, 5, 5, 5,
6689 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6690 6, 6, 6, 6, 6, 6,
6691 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6692 7, 7, 7, 7, 7, 7,
6693 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6694 8, 8, 8, 8, 8,
6695 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6696 9, 9, 9, 9, 9, 9,
6697 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6698 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6699 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6700 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6701
6702 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6703 0, 0, 0, 0, 0, 0,
6704 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6705 1, 1, 1,
6706 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6707 2, 2, 2, 2, 2, 2,
6708 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6709 3, 3, 3, 3, 3,
6710 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6711 4, 4, 4, 4, 4, 4,
6712 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6713 5, 5, 5, 5, 5,
6714 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6715 6, 6, 6, 6, 6, 6,
6716 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6717 7, 7, 7, 7, 7, 7,
6718 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6719 8, 8, 8, 8, 8,
6720 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6721 9, 9, 9, 9, 9, 9,
6722 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6723 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6724 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6725 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6726
6727
6728// This function works for dates from 1970 to 2099.
6729static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006730 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006731#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006732 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006733#endif
6734
6735 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6736 date %= kDaysIn4Years;
6737
6738 month = kMonthInYear[date];
6739 day = kDayInYear[date];
6740
6741 ASSERT(MakeDay(year, month, day) == save_date);
6742}
6743
6744
6745static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006746 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006747#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006748 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006749#endif
6750
6751 date += kDaysOffset;
6752 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6753 date %= kDaysIn400Years;
6754
6755 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6756
6757 date--;
6758 int yd1 = date / kDaysIn100Years;
6759 date %= kDaysIn100Years;
6760 year += 100 * yd1;
6761
6762 date++;
6763 int yd2 = date / kDaysIn4Years;
6764 date %= kDaysIn4Years;
6765 year += 4 * yd2;
6766
6767 date--;
6768 int yd3 = date / 365;
6769 date %= 365;
6770 year += yd3;
6771
6772 bool is_leap = (!yd1 || yd2) && !yd3;
6773
6774 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006775 ASSERT(is_leap || (date >= 0));
6776 ASSERT((date < 365) || (is_leap && (date < 366)));
6777 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6778 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6779 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006780
6781 if (is_leap) {
6782 day = kDayInYear[2*365 + 1 + date];
6783 month = kMonthInYear[2*365 + 1 + date];
6784 } else {
6785 day = kDayInYear[date];
6786 month = kMonthInYear[date];
6787 }
6788
6789 ASSERT(MakeDay(year, month, day) == save_date);
6790}
6791
6792
6793static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006794 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006795 if (date >= 0 && date < 32 * kDaysIn4Years) {
6796 DateYMDFromTimeAfter1970(date, year, month, day);
6797 } else {
6798 DateYMDFromTimeSlow(date, year, month, day);
6799 }
6800}
6801
6802
lrn@chromium.org303ada72010-10-27 09:33:13 +00006803static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006804 NoHandleAllocation ha;
6805 ASSERT(args.length() == 2);
6806
6807 CONVERT_DOUBLE_CHECKED(t, args[0]);
6808 CONVERT_CHECKED(JSArray, res_array, args[1]);
6809
6810 int year, month, day;
6811 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6812
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006813 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6814 FixedArray* elms = FixedArray::cast(res_array->elements());
6815 RUNTIME_ASSERT(elms->length() == 3);
6816
6817 elms->set(0, Smi::FromInt(year));
6818 elms->set(1, Smi::FromInt(month));
6819 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006820
6821 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006822}
6823
6824
lrn@chromium.org303ada72010-10-27 09:33:13 +00006825static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006826 NoHandleAllocation ha;
6827 ASSERT(args.length() == 3);
6828
6829 JSFunction* callee = JSFunction::cast(args[0]);
6830 Object** parameters = reinterpret_cast<Object**>(args[1]);
6831 const int length = Smi::cast(args[2])->value();
6832
lrn@chromium.org303ada72010-10-27 09:33:13 +00006833 Object* result;
6834 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6835 if (!maybe_result->ToObject(&result)) return maybe_result;
6836 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006837 // Allocate the elements if needed.
6838 if (length > 0) {
6839 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006840 Object* obj;
6841 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6842 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6843 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006844
6845 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006846 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6847 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006848 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006849
6850 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006851 for (int i = 0; i < length; i++) {
6852 array->set(i, *--parameters, mode);
6853 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006854 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006855 }
6856 return result;
6857}
6858
6859
lrn@chromium.org303ada72010-10-27 09:33:13 +00006860static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006861 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006862 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006863 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006864 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006865 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006866
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006867 // Allocate global closures in old space and allocate local closures
6868 // in new space. Additionally pretenure closures that are assigned
6869 // directly to properties.
6870 pretenure = pretenure || (context->global_context() == *context);
6871 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006872 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006873 Factory::NewFunctionFromSharedFunctionInfo(shared,
6874 context,
6875 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006876 return *result;
6877}
6878
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006879
lrn@chromium.org303ada72010-10-27 09:33:13 +00006880static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006881 HandleScope scope;
6882 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006883 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006884 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006885
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006886 // Second argument is either null or an array of bound arguments.
6887 FixedArray* bound_args = NULL;
6888 int bound_argc = 0;
6889 if (!args[1]->IsNull()) {
6890 CONVERT_ARG_CHECKED(JSArray, params, 1);
6891 RUNTIME_ASSERT(params->HasFastElements());
6892 bound_args = FixedArray::cast(params->elements());
6893 bound_argc = Smi::cast(params->length())->value();
6894 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006895
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006896 // Find frame containing arguments passed to the caller.
6897 JavaScriptFrameIterator it;
6898 JavaScriptFrame* frame = it.frame();
6899 ASSERT(!frame->is_optimized());
6900 it.AdvanceToArgumentsFrame();
6901 frame = it.frame();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00006902 int argc = frame->ComputeParametersCount();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006903
6904 // Prepend bound arguments to caller's arguments.
6905 int total_argc = bound_argc + argc;
6906 SmartPointer<Object**> param_data(NewArray<Object**>(total_argc));
6907 for (int i = 0; i < bound_argc; i++) {
6908 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006909 param_data[i] = val.location();
6910 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006911 for (int i = 0; i < argc; i++) {
6912 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
6913 param_data[bound_argc + i] = val.location();
6914 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006915
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006916 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006917 Handle<Object> result =
6918 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006919 if (exception) {
6920 return Failure::Exception();
6921 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006922
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006923 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006924 return *result;
6925}
6926
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006927
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006928static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006929 Handle<Object> prototype = Factory::null_value();
6930 if (function->has_instance_prototype()) {
6931 prototype = Handle<Object>(function->instance_prototype());
6932 }
6933 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006934 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006935 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006936 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006937 function->shared()->set_construct_stub(
6938 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006939 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006940 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006941}
6942
6943
lrn@chromium.org303ada72010-10-27 09:33:13 +00006944static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006945 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006946 ASSERT(args.length() == 1);
6947
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006948 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006949
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006950 // If the constructor isn't a proper function we throw a type error.
6951 if (!constructor->IsJSFunction()) {
6952 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6953 Handle<Object> type_error =
6954 Factory::NewTypeError("not_constructor", arguments);
6955 return Top::Throw(*type_error);
6956 }
6957
6958 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006959
6960 // If function should not have prototype, construction is not allowed. In this
6961 // case generated code bailouts here, since function has no initial_map.
6962 if (!function->should_have_prototype()) {
6963 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6964 Handle<Object> type_error =
6965 Factory::NewTypeError("not_constructor", arguments);
6966 return Top::Throw(*type_error);
6967 }
6968
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006969#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006970 // Handle stepping into constructors if step into is active.
6971 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006972 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006973 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006974#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006975
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006976 if (function->has_initial_map()) {
6977 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006978 // The 'Function' function ignores the receiver object when
6979 // called using 'new' and creates a new JSFunction object that
6980 // is returned. The receiver object is only used for error
6981 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006982 // JSFunction. Factory::NewJSObject() should not be used to
6983 // allocate JSFunctions since it does not properly initialize
6984 // the shared part of the function. Since the receiver is
6985 // ignored anyway, we use the global object as the receiver
6986 // instead of a new JSFunction object. This way, errors are
6987 // reported the same way whether or not 'Function' is called
6988 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006989 return Top::context()->global();
6990 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006991 }
6992
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006993 // The function should be compiled for the optimization hints to be
6994 // available. We cannot use EnsureCompiled because that forces a
6995 // compilation through the shared function info which makes it
6996 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006997 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006998 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006999
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007000 if (!function->has_initial_map() &&
7001 shared->IsInobjectSlackTrackingInProgress()) {
7002 // The tracking is already in progress for another function. We can only
7003 // track one initial_map at a time, so we force the completion before the
7004 // function is called as a constructor for the first time.
7005 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007006 }
7007
7008 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007009 Handle<JSObject> result = Factory::NewJSObject(function);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007010 RETURN_IF_EMPTY_HANDLE(result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007011 // Delay setting the stub if inobject slack tracking is in progress.
7012 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
7013 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007014 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007015
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007016 Counters::constructed_objects.Increment();
7017 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007018
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007019 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007020}
7021
7022
lrn@chromium.org303ada72010-10-27 09:33:13 +00007023static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007024 HandleScope scope;
7025 ASSERT(args.length() == 1);
7026
7027 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7028 function->shared()->CompleteInobjectSlackTracking();
7029 TrySettingInlineConstructStub(function);
7030
7031 return Heap::undefined_value();
7032}
7033
7034
lrn@chromium.org303ada72010-10-27 09:33:13 +00007035static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007036 HandleScope scope;
7037 ASSERT(args.length() == 1);
7038
7039 Handle<JSFunction> function = args.at<JSFunction>(0);
7040#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007041 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007042 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007043 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007044 PrintF("]\n");
7045 }
7046#endif
7047
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007048 // Compile the target function. Here we compile using CompileLazyInLoop in
7049 // order to get the optimized version. This helps code like delta-blue
7050 // that calls performance-critical routines through constructors. A
7051 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7052 // direct call. Since the in-loop tracking takes place through CallICs
7053 // this means that things called through constructors are never known to
7054 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007055 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007056 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007057 return Failure::Exception();
7058 }
7059
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007060 // All done. Return the compiled code.
7061 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007062 return function->code();
7063}
7064
7065
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007066static MaybeObject* Runtime_LazyRecompile(Arguments args) {
7067 HandleScope scope;
7068 ASSERT(args.length() == 1);
7069 Handle<JSFunction> function = args.at<JSFunction>(0);
7070 // If the function is not optimizable or debugger is active continue using the
7071 // code from the full compiler.
7072 if (!function->shared()->code()->optimizable() ||
7073 Debug::has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007074 if (FLAG_trace_opt) {
7075 PrintF("[failed to optimize ");
7076 function->PrintName();
7077 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7078 function->shared()->code()->optimizable() ? "T" : "F",
7079 Debug::has_break_points() ? "T" : "F");
7080 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007081 function->ReplaceCode(function->shared()->code());
7082 return function->code();
7083 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007084 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007085 return function->code();
7086 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007087 if (FLAG_trace_opt) {
7088 PrintF("[failed to optimize ");
7089 function->PrintName();
7090 PrintF(": optimized compilation failed]\n");
7091 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007092 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007093 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007094}
7095
7096
7097static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
7098 HandleScope scope;
7099 ASSERT(args.length() == 1);
7100 RUNTIME_ASSERT(args[0]->IsSmi());
7101 Deoptimizer::BailoutType type =
7102 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
7103 Deoptimizer* deoptimizer = Deoptimizer::Grab();
7104 ASSERT(Heap::IsAllocationAllowed());
7105 int frames = deoptimizer->output_count();
7106
7107 JavaScriptFrameIterator it;
7108 JavaScriptFrame* frame = NULL;
7109 for (int i = 0; i < frames; i++) {
7110 if (i != 0) it.Advance();
7111 frame = it.frame();
7112 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
7113 }
7114 delete deoptimizer;
7115
7116 RUNTIME_ASSERT(frame->function()->IsJSFunction());
7117 Handle<JSFunction> function(JSFunction::cast(frame->function()));
7118 Handle<Object> arguments;
7119 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00007120 if (frame->GetExpression(i) == Heap::arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007121 if (arguments.is_null()) {
7122 // FunctionGetArguments can't throw an exception, so cast away the
7123 // doubt with an assert.
7124 arguments = Handle<Object>(
7125 Accessors::FunctionGetArguments(*function,
7126 NULL)->ToObjectUnchecked());
7127 ASSERT(*arguments != Heap::null_value());
7128 ASSERT(*arguments != Heap::undefined_value());
7129 }
7130 frame->SetExpression(i, *arguments);
7131 }
7132 }
7133
7134 CompilationCache::MarkForLazyOptimizing(function);
7135 if (type == Deoptimizer::EAGER) {
7136 RUNTIME_ASSERT(function->IsOptimized());
7137 } else {
7138 RUNTIME_ASSERT(!function->IsOptimized());
7139 }
7140
7141 // Avoid doing too much work when running with --always-opt and keep
7142 // the optimized code around.
7143 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
7144 return Heap::undefined_value();
7145 }
7146
7147 // Count the number of optimized activations of the function.
7148 int activations = 0;
7149 while (!it.done()) {
7150 JavaScriptFrame* frame = it.frame();
7151 if (frame->is_optimized() && frame->function() == *function) {
7152 activations++;
7153 }
7154 it.Advance();
7155 }
7156
7157 // TODO(kasperl): For now, we cannot support removing the optimized
7158 // code when we have recursive invocations of the same function.
7159 if (activations == 0) {
7160 if (FLAG_trace_deopt) {
7161 PrintF("[removing optimized code for: ");
7162 function->PrintName();
7163 PrintF("]\n");
7164 }
7165 function->ReplaceCode(function->shared()->code());
7166 }
7167 return Heap::undefined_value();
7168}
7169
7170
7171static MaybeObject* Runtime_NotifyOSR(Arguments args) {
7172 Deoptimizer* deoptimizer = Deoptimizer::Grab();
7173 delete deoptimizer;
7174 return Heap::undefined_value();
7175}
7176
7177
7178static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
7179 HandleScope scope;
7180 ASSERT(args.length() == 1);
7181 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7182 if (!function->IsOptimized()) return Heap::undefined_value();
7183
7184 Deoptimizer::DeoptimizeFunction(*function);
7185
7186 return Heap::undefined_value();
7187}
7188
7189
7190static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
7191 HandleScope scope;
7192 ASSERT(args.length() == 1);
7193 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7194
7195 // We're not prepared to handle a function with arguments object.
7196 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7197
7198 // We have hit a back edge in an unoptimized frame for a function that was
7199 // selected for on-stack replacement. Find the unoptimized code object.
7200 Handle<Code> unoptimized(function->shared()->code());
7201 // Keep track of whether we've succeeded in optimizing.
7202 bool succeeded = unoptimized->optimizable();
7203 if (succeeded) {
7204 // If we are trying to do OSR when there are already optimized
7205 // activations of the function, it means (a) the function is directly or
7206 // indirectly recursive and (b) an optimized invocation has been
7207 // deoptimized so that we are currently in an unoptimized activation.
7208 // Check for optimized activations of this function.
7209 JavaScriptFrameIterator it;
7210 while (succeeded && !it.done()) {
7211 JavaScriptFrame* frame = it.frame();
7212 succeeded = !frame->is_optimized() || frame->function() != *function;
7213 it.Advance();
7214 }
7215 }
7216
7217 int ast_id = AstNode::kNoNumber;
7218 if (succeeded) {
7219 // The top JS function is this one, the PC is somewhere in the
7220 // unoptimized code.
7221 JavaScriptFrameIterator it;
7222 JavaScriptFrame* frame = it.frame();
7223 ASSERT(frame->function() == *function);
7224 ASSERT(frame->code() == *unoptimized);
7225 ASSERT(unoptimized->contains(frame->pc()));
7226
7227 // Use linear search of the unoptimized code's stack check table to find
7228 // the AST id matching the PC.
7229 Address start = unoptimized->instruction_start();
7230 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007231 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007232 uint32_t table_length = Memory::uint32_at(table_cursor);
7233 table_cursor += kIntSize;
7234 for (unsigned i = 0; i < table_length; ++i) {
7235 // Table entries are (AST id, pc offset) pairs.
7236 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7237 if (pc_offset == target_pc_offset) {
7238 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7239 break;
7240 }
7241 table_cursor += 2 * kIntSize;
7242 }
7243 ASSERT(ast_id != AstNode::kNoNumber);
7244 if (FLAG_trace_osr) {
7245 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7246 function->PrintName();
7247 PrintF("]\n");
7248 }
7249
7250 // Try to compile the optimized code. A true return value from
7251 // CompileOptimized means that compilation succeeded, not necessarily
7252 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007253 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7254 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007255 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7256 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007257 if (data->OsrPcOffset()->value() >= 0) {
7258 if (FLAG_trace_osr) {
7259 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007260 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007261 }
7262 ASSERT(data->OsrAstId()->value() == ast_id);
7263 } else {
7264 // We may never generate the desired OSR entry if we emit an
7265 // early deoptimize.
7266 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007267 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007268 } else {
7269 succeeded = false;
7270 }
7271 }
7272
7273 // Revert to the original stack checks in the original unoptimized code.
7274 if (FLAG_trace_osr) {
7275 PrintF("[restoring original stack checks in ");
7276 function->PrintName();
7277 PrintF("]\n");
7278 }
7279 StackCheckStub check_stub;
7280 Handle<Code> check_code = check_stub.GetCode();
7281 Handle<Code> replacement_code(
7282 Builtins::builtin(Builtins::OnStackReplacement));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007283 Deoptimizer::RevertStackCheckCode(*unoptimized,
7284 *check_code,
7285 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007286
7287 // Allow OSR only at nesting level zero again.
7288 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7289
7290 // If the optimization attempt succeeded, return the AST id tagged as a
7291 // smi. This tells the builtin that we need to translate the unoptimized
7292 // frame to an optimized one.
7293 if (succeeded) {
7294 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7295 return Smi::FromInt(ast_id);
7296 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007297 if (function->IsMarkedForLazyRecompilation()) {
7298 function->ReplaceCode(function->shared()->code());
7299 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007300 return Smi::FromInt(-1);
7301 }
7302}
7303
7304
lrn@chromium.org303ada72010-10-27 09:33:13 +00007305static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007306 HandleScope scope;
7307 ASSERT(args.length() == 1);
7308 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7309 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7310}
7311
7312
lrn@chromium.org303ada72010-10-27 09:33:13 +00007313static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007314 HandleScope scope;
7315 ASSERT(args.length() == 1);
7316 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7317 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7318}
7319
7320
lrn@chromium.org303ada72010-10-27 09:33:13 +00007321static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007322 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007323 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007324
kasper.lund7276f142008-07-30 08:49:36 +00007325 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007326 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007327 Object* result;
7328 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
7329 if (!maybe_result->ToObject(&result)) return maybe_result;
7330 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007331
7332 Top::set_context(Context::cast(result));
7333
kasper.lund7276f142008-07-30 08:49:36 +00007334 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007335}
7336
lrn@chromium.org303ada72010-10-27 09:33:13 +00007337
7338MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
7339 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007340 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007341 Object* js_object = object;
7342 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007343 MaybeObject* maybe_js_object = js_object->ToObject();
7344 if (!maybe_js_object->ToObject(&js_object)) {
7345 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7346 return maybe_js_object;
7347 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007349 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007350 Handle<Object> result =
7351 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
7352 return Top::Throw(*result);
7353 }
7354 }
7355
lrn@chromium.org303ada72010-10-27 09:33:13 +00007356 Object* result;
7357 { MaybeObject* maybe_result =
7358 Heap::AllocateWithContext(Top::context(),
7359 JSObject::cast(js_object),
7360 is_catch_context);
7361 if (!maybe_result->ToObject(&result)) return maybe_result;
7362 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007363
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007364 Context* context = Context::cast(result);
7365 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007366
kasper.lund7276f142008-07-30 08:49:36 +00007367 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007368}
7369
7370
lrn@chromium.org303ada72010-10-27 09:33:13 +00007371static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007372 NoHandleAllocation ha;
7373 ASSERT(args.length() == 1);
7374 return PushContextHelper(args[0], false);
7375}
7376
7377
lrn@chromium.org303ada72010-10-27 09:33:13 +00007378static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007379 NoHandleAllocation ha;
7380 ASSERT(args.length() == 1);
7381 return PushContextHelper(args[0], true);
7382}
7383
7384
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007385static MaybeObject* Runtime_DeleteContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007386 HandleScope scope;
7387 ASSERT(args.length() == 2);
7388
7389 CONVERT_ARG_CHECKED(Context, context, 0);
7390 CONVERT_ARG_CHECKED(String, name, 1);
7391
7392 int index;
7393 PropertyAttributes attributes;
7394 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007395 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007396
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007397 // If the slot was not found the result is true.
7398 if (holder.is_null()) {
7399 return Heap::true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400 }
7401
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007402 // If the slot was found in a context, it should be DONT_DELETE.
7403 if (holder->IsContext()) {
7404 return Heap::false_value();
7405 }
7406
7407 // The slot was found in a JSObject, either a context extension object,
7408 // the global object, or an arguments object. Try to delete it
7409 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7410 // which allows deleting all parameters in functions that mention
7411 // 'arguments', we do this even for the case of slots found on an
7412 // arguments object. The slot was found on an arguments object if the
7413 // index is non-negative.
7414 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7415 if (index >= 0) {
7416 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7417 } else {
7418 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7419 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420}
7421
7422
ager@chromium.orga1645e22009-09-09 19:27:10 +00007423// A mechanism to return a pair of Object pointers in registers (if possible).
7424// How this is achieved is calling convention-dependent.
7425// All currently supported x86 compiles uses calling conventions that are cdecl
7426// variants where a 64-bit value is returned in two 32-bit registers
7427// (edx:eax on ia32, r1:r0 on ARM).
7428// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7429// In Win64 calling convention, a struct of two pointers is returned in memory,
7430// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007431#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007432struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007433 MaybeObject* x;
7434 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007435};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007436
lrn@chromium.org303ada72010-10-27 09:33:13 +00007437static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007438 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007439 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7440 // In Win64 they are assigned to a hidden first argument.
7441 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007442}
7443#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007444typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007445static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007446 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007447 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007448}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007449#endif
7450
7451
lrn@chromium.org303ada72010-10-27 09:33:13 +00007452static inline MaybeObject* Unhole(MaybeObject* x,
7453 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7455 USE(attributes);
7456 return x->IsTheHole() ? Heap::undefined_value() : x;
7457}
7458
7459
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007460static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7461 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007462 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007463 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007464 JSFunction* context_extension_function =
7465 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007466 // If the holder isn't a context extension object, we just return it
7467 // as the receiver. This allows arguments objects to be used as
7468 // receivers, but only if they are put in the context scope chain
7469 // explicitly via a with-statement.
7470 Object* constructor = holder->map()->constructor();
7471 if (constructor != context_extension_function) return holder;
7472 // Fall back to using the global object as the receiver if the
7473 // property turns out to be a local variable allocated in a context
7474 // extension object - introduced via eval.
7475 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007476}
7477
7478
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007479static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007480 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007481 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007482
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007483 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007484 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007485 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007486 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007487 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007488
7489 int index;
7490 PropertyAttributes attributes;
7491 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007492 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007493
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007494 // If the index is non-negative, the slot has been found in a local
7495 // variable or a parameter. Read it from the context object or the
7496 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007497 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007498 // If the "property" we were looking for is a local variable or an
7499 // argument in a context, the receiver is the global object; see
7500 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7501 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007502 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007503 ? Context::cast(*holder)->get(index)
7504 : JSObject::cast(*holder)->GetElement(index);
7505 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007506 }
7507
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007508 // If the holder is found, we read the property from it.
7509 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007510 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007511 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007512 JSObject* receiver;
7513 if (object->IsGlobalObject()) {
7514 receiver = GlobalObject::cast(object)->global_receiver();
7515 } else if (context->is_exception_holder(*holder)) {
7516 receiver = Top::context()->global()->global_receiver();
7517 } else {
7518 receiver = ComputeReceiverForNonGlobal(object);
7519 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007520 // No need to unhole the value here. This is taken care of by the
7521 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007522 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007523 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007524 }
7525
7526 if (throw_error) {
7527 // The property doesn't exist - throw exception.
7528 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007529 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007530 return MakePair(Top::Throw(*reference_error), NULL);
7531 } else {
7532 // The property doesn't exist - return undefined
7533 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7534 }
7535}
7536
7537
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007538static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007539 return LoadContextSlotHelper(args, true);
7540}
7541
7542
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007543static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007544 return LoadContextSlotHelper(args, false);
7545}
7546
7547
lrn@chromium.org303ada72010-10-27 09:33:13 +00007548static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007549 HandleScope scope;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007550 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007551
7552 Handle<Object> value(args[0]);
7553 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007554 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007555 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7556 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7557 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007558 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007559
7560 int index;
7561 PropertyAttributes attributes;
7562 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007563 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007564
7565 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007566 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007567 // Ignore if read_only variable.
7568 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007569 // Context is a fixed array and set cannot fail.
7570 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007571 } else if (strict_mode == kStrictMode) {
7572 // Setting read only property in strict mode.
7573 Handle<Object> error =
7574 Factory::NewTypeError("strict_cannot_assign",
7575 HandleVector(&name, 1));
7576 return Top::Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007577 }
7578 } else {
7579 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007580 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007581 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007582 if (result.is_null()) {
7583 ASSERT(Top::has_pending_exception());
7584 return Failure::Exception();
7585 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007586 }
7587 return *value;
7588 }
7589
7590 // Slow case: The property is not in a FixedArray context.
7591 // It is either in an JSObject extension context or it was not found.
7592 Handle<JSObject> context_ext;
7593
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007594 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007595 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007596 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007597 } else {
7598 // The property was not found. It needs to be stored in the global context.
7599 ASSERT(attributes == ABSENT);
7600 attributes = NONE;
7601 context_ext = Handle<JSObject>(Top::context()->global());
7602 }
7603
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007604 // Set the property, but ignore if read_only variable on the context
7605 // extension object itself.
7606 if ((attributes & READ_ONLY) == 0 ||
7607 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007608 RETURN_IF_EMPTY_HANDLE(
7609 SetProperty(context_ext, name, value, NONE, strict_mode));
7610 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007611 // Setting read only property in strict mode.
7612 Handle<Object> error =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007613 Factory::NewTypeError("strict_cannot_assign", HandleVector(&name, 1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007614 return Top::Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007615 }
7616 return *value;
7617}
7618
7619
lrn@chromium.org303ada72010-10-27 09:33:13 +00007620static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007621 HandleScope scope;
7622 ASSERT(args.length() == 1);
7623
7624 return Top::Throw(args[0]);
7625}
7626
7627
lrn@chromium.org303ada72010-10-27 09:33:13 +00007628static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007629 HandleScope scope;
7630 ASSERT(args.length() == 1);
7631
7632 return Top::ReThrow(args[0]);
7633}
7634
7635
lrn@chromium.org303ada72010-10-27 09:33:13 +00007636static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007637 ASSERT_EQ(0, args.length());
7638 return Top::PromoteScheduledException();
7639}
7640
7641
lrn@chromium.org303ada72010-10-27 09:33:13 +00007642static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007643 HandleScope scope;
7644 ASSERT(args.length() == 1);
7645
7646 Handle<Object> name(args[0]);
7647 Handle<Object> reference_error =
7648 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7649 return Top::Throw(*reference_error);
7650}
7651
7652
lrn@chromium.org303ada72010-10-27 09:33:13 +00007653static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007654 NoHandleAllocation na;
7655 return Top::StackOverflow();
7656}
7657
7658
lrn@chromium.org303ada72010-10-27 09:33:13 +00007659static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007660 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007661
7662 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007663 if (StackGuard::IsStackOverflow()) {
7664 return Runtime_StackOverflow(args);
7665 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007666
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007667 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007668}
7669
7670
7671// NOTE: These PrintXXX functions are defined for all builds (not just
7672// DEBUG builds) because we may want to be able to trace function
7673// calls in all modes.
7674static void PrintString(String* str) {
7675 // not uncommon to have empty strings
7676 if (str->length() > 0) {
7677 SmartPointer<char> s =
7678 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7679 PrintF("%s", *s);
7680 }
7681}
7682
7683
7684static void PrintObject(Object* obj) {
7685 if (obj->IsSmi()) {
7686 PrintF("%d", Smi::cast(obj)->value());
7687 } else if (obj->IsString() || obj->IsSymbol()) {
7688 PrintString(String::cast(obj));
7689 } else if (obj->IsNumber()) {
7690 PrintF("%g", obj->Number());
7691 } else if (obj->IsFailure()) {
7692 PrintF("<failure>");
7693 } else if (obj->IsUndefined()) {
7694 PrintF("<undefined>");
7695 } else if (obj->IsNull()) {
7696 PrintF("<null>");
7697 } else if (obj->IsTrue()) {
7698 PrintF("<true>");
7699 } else if (obj->IsFalse()) {
7700 PrintF("<false>");
7701 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007702 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007703 }
7704}
7705
7706
7707static int StackSize() {
7708 int n = 0;
7709 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7710 return n;
7711}
7712
7713
7714static void PrintTransition(Object* result) {
7715 // indentation
7716 { const int nmax = 80;
7717 int n = StackSize();
7718 if (n <= nmax)
7719 PrintF("%4d:%*s", n, n, "");
7720 else
7721 PrintF("%4d:%*s", n, nmax, "...");
7722 }
7723
7724 if (result == NULL) {
7725 // constructor calls
7726 JavaScriptFrameIterator it;
7727 JavaScriptFrame* frame = it.frame();
7728 if (frame->IsConstructor()) PrintF("new ");
7729 // function name
7730 Object* fun = frame->function();
7731 if (fun->IsJSFunction()) {
7732 PrintObject(JSFunction::cast(fun)->shared()->name());
7733 } else {
7734 PrintObject(fun);
7735 }
7736 // function arguments
7737 // (we are intentionally only printing the actually
7738 // supplied parameters, not all parameters required)
7739 PrintF("(this=");
7740 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007741 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007742 for (int i = 0; i < length; i++) {
7743 PrintF(", ");
7744 PrintObject(frame->GetParameter(i));
7745 }
7746 PrintF(") {\n");
7747
7748 } else {
7749 // function result
7750 PrintF("} -> ");
7751 PrintObject(result);
7752 PrintF("\n");
7753 }
7754}
7755
7756
lrn@chromium.org303ada72010-10-27 09:33:13 +00007757static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007758 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007759 NoHandleAllocation ha;
7760 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007761 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007762}
7763
7764
lrn@chromium.org303ada72010-10-27 09:33:13 +00007765static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007766 NoHandleAllocation ha;
7767 PrintTransition(args[0]);
7768 return args[0]; // return TOS
7769}
7770
7771
lrn@chromium.org303ada72010-10-27 09:33:13 +00007772static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007773 NoHandleAllocation ha;
7774 ASSERT(args.length() == 1);
7775
7776#ifdef DEBUG
7777 if (args[0]->IsString()) {
7778 // If we have a string, assume it's a code "marker"
7779 // and print some interesting cpu debugging info.
7780 JavaScriptFrameIterator it;
7781 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007782 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7783 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007784 } else {
7785 PrintF("DebugPrint: ");
7786 }
7787 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007788 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007789 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007790 HeapObject::cast(args[0])->map()->Print();
7791 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007792#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007793 // ShortPrint is available in release mode. Print is not.
7794 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007795#endif
7796 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007797 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007798
7799 return args[0]; // return TOS
7800}
7801
7802
lrn@chromium.org303ada72010-10-27 09:33:13 +00007803static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007804 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007805 NoHandleAllocation ha;
7806 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007807 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007808}
7809
7810
lrn@chromium.org303ada72010-10-27 09:33:13 +00007811static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007812 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007813 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007814
7815 // According to ECMA-262, section 15.9.1, page 117, the precision of
7816 // the number in a Date object representing a particular instant in
7817 // time is milliseconds. Therefore, we floor the result of getting
7818 // the OS time.
7819 double millis = floor(OS::TimeCurrentMillis());
7820 return Heap::NumberFromDouble(millis);
7821}
7822
7823
lrn@chromium.org303ada72010-10-27 09:33:13 +00007824static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007825 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007826 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007827
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007828 CONVERT_ARG_CHECKED(String, str, 0);
7829 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007830
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007831 CONVERT_ARG_CHECKED(JSArray, output, 1);
7832 RUNTIME_ASSERT(output->HasFastElements());
7833
7834 AssertNoAllocation no_allocation;
7835
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007836 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007837 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7838 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007839 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007840 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007841 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007842 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007843 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7844 }
7845
7846 if (result) {
7847 return *output;
7848 } else {
7849 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007850 }
7851}
7852
7853
lrn@chromium.org303ada72010-10-27 09:33:13 +00007854static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007855 NoHandleAllocation ha;
7856 ASSERT(args.length() == 1);
7857
7858 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007859 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007860 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7861}
7862
7863
lrn@chromium.org303ada72010-10-27 09:33:13 +00007864static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007865 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007866 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007867
7868 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7869}
7870
7871
lrn@chromium.org303ada72010-10-27 09:33:13 +00007872static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007873 NoHandleAllocation ha;
7874 ASSERT(args.length() == 1);
7875
7876 CONVERT_DOUBLE_CHECKED(x, args[0]);
7877 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7878}
7879
7880
lrn@chromium.org303ada72010-10-27 09:33:13 +00007881static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007882 ASSERT(args.length() == 1);
7883 Object* global = args[0];
7884 if (!global->IsJSGlobalObject()) return Heap::null_value();
7885 return JSGlobalObject::cast(global)->global_receiver();
7886}
7887
7888
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007889static MaybeObject* Runtime_ParseJson(Arguments args) {
7890 HandleScope scope;
7891 ASSERT_EQ(1, args.length());
7892 CONVERT_ARG_CHECKED(String, source, 0);
7893
7894 Handle<Object> result = JsonParser::Parse(source);
7895 if (result.is_null()) {
7896 // Syntax error or stack overflow in scanner.
7897 ASSERT(Top::has_pending_exception());
7898 return Failure::Exception();
7899 }
7900 return *result;
7901}
7902
7903
lrn@chromium.org303ada72010-10-27 09:33:13 +00007904static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007905 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007906 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007907 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007908
ager@chromium.org381abbb2009-02-25 13:23:22 +00007909 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007910 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007911 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7912 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007913 true,
7914 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007915 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007916 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007917 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007918 return *fun;
7919}
7920
7921
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007922static ObjectPair CompileGlobalEval(Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007923 Handle<Object> receiver,
7924 StrictModeFlag mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007925 // Deal with a normal eval call with a string argument. Compile it
7926 // and return the compiled function bound in the local context.
7927 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7928 source,
7929 Handle<Context>(Top::context()),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007930 Top::context()->IsGlobalContext(),
7931 mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007932 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7933 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7934 shared,
7935 Handle<Context>(Top::context()),
7936 NOT_TENURED);
7937 return MakePair(*compiled, *receiver);
7938}
7939
7940
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007941static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007942 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007943
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007944 HandleScope scope;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007945 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007946 Handle<Object> receiver; // Will be overwritten.
7947
7948 // Compute the calling context.
7949 Handle<Context> context = Handle<Context>(Top::context());
7950#ifdef DEBUG
7951 // Make sure Top::context() agrees with the old code that traversed
7952 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007953 StackFrameLocator locator;
7954 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007955 ASSERT(Context::cast(frame->context()) == *context);
7956#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007957
7958 // Find where the 'eval' symbol is bound. It is unaliased only if
7959 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007960 int index = -1;
7961 PropertyAttributes attributes = ABSENT;
7962 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007963 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7964 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007965 // Stop search when eval is found or when the global context is
7966 // reached.
7967 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007968 if (context->is_function_context()) {
7969 context = Handle<Context>(Context::cast(context->closure()->context()));
7970 } else {
7971 context = Handle<Context>(context->previous());
7972 }
7973 }
7974
iposva@chromium.org245aa852009-02-10 00:49:54 +00007975 // If eval could not be resolved, it has been deleted and we need to
7976 // throw a reference error.
7977 if (attributes == ABSENT) {
7978 Handle<Object> name = Factory::eval_symbol();
7979 Handle<Object> reference_error =
7980 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007981 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007982 }
7983
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007984 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007985 // 'eval' is not bound in the global context. Just call the function
7986 // with the given arguments. This is not necessarily the global eval.
7987 if (receiver->IsContext()) {
7988 context = Handle<Context>::cast(receiver);
7989 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007990 } else if (receiver->IsJSContextExtensionObject()) {
7991 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007992 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007993 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007994 }
7995
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007996 // 'eval' is bound in the global context, but it may have been overwritten.
7997 // Compare it to the builtin 'GlobalEval' function to make sure.
7998 if (*callee != Top::global_context()->global_eval_fun() ||
7999 !args[1]->IsString()) {
8000 return MakePair(*callee, Top::context()->global()->global_receiver());
8001 }
8002
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008003 ASSERT(args[3]->IsSmi());
8004 return CompileGlobalEval(args.at<String>(1),
8005 args.at<Object>(2),
8006 static_cast<StrictModeFlag>(
8007 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008008}
8009
8010
8011static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008012 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008013
8014 HandleScope scope;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008015 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008016
8017 // 'eval' is bound in the global context, but it may have been overwritten.
8018 // Compare it to the builtin 'GlobalEval' function to make sure.
8019 if (*callee != Top::global_context()->global_eval_fun() ||
8020 !args[1]->IsString()) {
8021 return MakePair(*callee, Top::context()->global()->global_receiver());
8022 }
8023
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008024 ASSERT(args[3]->IsSmi());
8025 return CompileGlobalEval(args.at<String>(1),
8026 args.at<Object>(2),
8027 static_cast<StrictModeFlag>(
8028 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008029}
8030
8031
lrn@chromium.org303ada72010-10-27 09:33:13 +00008032static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008033 // This utility adjusts the property attributes for newly created Function
8034 // object ("new Function(...)") by changing the map.
8035 // All it does is changing the prototype property to enumerable
8036 // as specified in ECMA262, 15.3.5.2.
8037 HandleScope scope;
8038 ASSERT(args.length() == 1);
8039 CONVERT_ARG_CHECKED(JSFunction, func, 0);
8040 ASSERT(func->map()->instance_type() ==
8041 Top::function_instance_map()->instance_type());
8042 ASSERT(func->map()->instance_size() ==
8043 Top::function_instance_map()->instance_size());
8044 func->set_map(*Top::function_instance_map());
8045 return *func;
8046}
8047
8048
lrn@chromium.org303ada72010-10-27 09:33:13 +00008049static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008050 // Allocate a block of memory in NewSpace (filled with a filler).
8051 // Use as fallback for allocation in generated code when NewSpace
8052 // is full.
8053 ASSERT(args.length() == 1);
8054 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8055 int size = size_smi->value();
8056 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8057 RUNTIME_ASSERT(size > 0);
8058 static const int kMinFreeNewSpaceAfterGC =
8059 Heap::InitialSemiSpaceSize() * 3/4;
8060 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008061 Object* allocation;
8062 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
8063 if (maybe_allocation->ToObject(&allocation)) {
8064 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
8065 }
8066 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008067 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008068}
8069
8070
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008071// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008072// array. Returns true if the element was pushed on the stack and
8073// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008074static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008075 ASSERT(args.length() == 2);
8076 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008077 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008078 RUNTIME_ASSERT(array->HasFastElements());
8079 int length = Smi::cast(array->length())->value();
8080 FixedArray* elements = FixedArray::cast(array->elements());
8081 for (int i = 0; i < length; i++) {
8082 if (elements->get(i) == element) return Heap::false_value();
8083 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008084 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008085 // Strict not needed. Used for cycle detection in Array join implementation.
8086 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8087 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008088 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8089 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008090 return Heap::true_value();
8091}
8092
8093
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008094/**
8095 * A simple visitor visits every element of Array's.
8096 * The backend storage can be a fixed array for fast elements case,
8097 * or a dictionary for sparse array. Since Dictionary is a subtype
8098 * of FixedArray, the class can be used by both fast and slow cases.
8099 * The second parameter of the constructor, fast_elements, specifies
8100 * whether the storage is a FixedArray or Dictionary.
8101 *
8102 * An index limit is used to deal with the situation that a result array
8103 * length overflows 32-bit non-negative integer.
8104 */
8105class ArrayConcatVisitor {
8106 public:
8107 ArrayConcatVisitor(Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008108 bool fast_elements) :
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008109 storage_(Handle<FixedArray>::cast(GlobalHandles::Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008110 index_offset_(0u),
8111 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008112
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008113 ~ArrayConcatVisitor() {
8114 clear_storage();
8115 }
8116
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008117 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008118 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008119 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008120
8121 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008122 if (index < static_cast<uint32_t>(storage_->length())) {
8123 storage_->set(index, *elm);
8124 return;
8125 }
8126 // Our initial estimate of length was foiled, possibly by
8127 // getters on the arrays increasing the length of later arrays
8128 // during iteration.
8129 // This shouldn't happen in anything but pathological cases.
8130 SetDictionaryMode(index);
8131 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008132 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008133 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008134 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008135 Handle<NumberDictionary> result =
8136 Factory::DictionaryAtNumberPut(dict, index, elm);
8137 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008138 // Dictionary needed to grow.
8139 clear_storage();
8140 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008141 }
8142}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008143
8144 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008145 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8146 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008147 } else {
8148 index_offset_ += delta;
8149 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008150 }
8151
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008152 Handle<JSArray> ToArray() {
8153 Handle<JSArray> array = Factory::NewJSArray(0);
8154 Handle<Object> length =
8155 Factory::NewNumber(static_cast<double>(index_offset_));
8156 Handle<Map> map;
8157 if (fast_elements_) {
8158 map = Factory::GetFastElementsMap(Handle<Map>(array->map()));
8159 } else {
8160 map = Factory::GetSlowElementsMap(Handle<Map>(array->map()));
8161 }
8162 array->set_map(*map);
8163 array->set_length(*length);
8164 array->set_elements(*storage_);
8165 return array;
8166 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008167
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008168 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008169 // Convert storage to dictionary mode.
8170 void SetDictionaryMode(uint32_t index) {
8171 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008172 Handle<FixedArray> current_storage(*storage_);
8173 Handle<NumberDictionary> slow_storage(
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008174 Factory::NewNumberDictionary(current_storage->length()));
8175 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8176 for (uint32_t i = 0; i < current_length; i++) {
8177 HandleScope loop_scope;
8178 Handle<Object> element(current_storage->get(i));
8179 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008180 Handle<NumberDictionary> new_storage =
8181 Factory::DictionaryAtNumberPut(slow_storage, i, element);
8182 if (!new_storage.is_identical_to(slow_storage)) {
8183 slow_storage = loop_scope.CloseAndEscape(new_storage);
8184 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008185 }
8186 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008187 clear_storage();
8188 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008189 fast_elements_ = false;
8190 }
8191
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008192 inline void clear_storage() {
8193 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
8194 }
8195
8196 inline void set_storage(FixedArray* storage) {
8197 storage_ = Handle<FixedArray>::cast(GlobalHandles::Create(storage));
8198 }
8199
8200 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008201 // Index after last seen index. Always less than or equal to
8202 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008203 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008204 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008205};
8206
8207
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008208static uint32_t EstimateElementCount(Handle<JSArray> array) {
8209 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8210 int element_count = 0;
8211 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008212 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008213 // Fast elements can't have lengths that are not representable by
8214 // a 32-bit signed integer.
8215 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8216 int fast_length = static_cast<int>(length);
8217 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8218 for (int i = 0; i < fast_length; i++) {
8219 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008220 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008221 break;
8222 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008223 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008224 Handle<NumberDictionary> dictionary(
8225 NumberDictionary::cast(array->elements()));
8226 int capacity = dictionary->Capacity();
8227 for (int i = 0; i < capacity; i++) {
8228 Handle<Object> key(dictionary->KeyAt(i));
8229 if (dictionary->IsKey(*key)) {
8230 element_count++;
8231 }
8232 }
8233 break;
8234 }
8235 default:
8236 // External arrays are always dense.
8237 return length;
8238 }
8239 // As an estimate, we assume that the prototype doesn't contain any
8240 // inherited elements.
8241 return element_count;
8242}
8243
8244
8245
8246template<class ExternalArrayClass, class ElementType>
8247static void IterateExternalArrayElements(Handle<JSObject> receiver,
8248 bool elements_are_ints,
8249 bool elements_are_guaranteed_smis,
8250 ArrayConcatVisitor* visitor) {
8251 Handle<ExternalArrayClass> array(
8252 ExternalArrayClass::cast(receiver->elements()));
8253 uint32_t len = static_cast<uint32_t>(array->length());
8254
8255 ASSERT(visitor != NULL);
8256 if (elements_are_ints) {
8257 if (elements_are_guaranteed_smis) {
8258 for (uint32_t j = 0; j < len; j++) {
8259 HandleScope loop_scope;
8260 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8261 visitor->visit(j, e);
8262 }
8263 } else {
8264 for (uint32_t j = 0; j < len; j++) {
8265 HandleScope loop_scope;
8266 int64_t val = static_cast<int64_t>(array->get(j));
8267 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8268 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8269 visitor->visit(j, e);
8270 } else {
8271 Handle<Object> e =
8272 Factory::NewNumber(static_cast<ElementType>(val));
8273 visitor->visit(j, e);
8274 }
8275 }
8276 }
8277 } else {
8278 for (uint32_t j = 0; j < len; j++) {
8279 HandleScope loop_scope;
8280 Handle<Object> e = Factory::NewNumber(array->get(j));
8281 visitor->visit(j, e);
8282 }
8283 }
8284}
8285
8286
8287// Used for sorting indices in a List<uint32_t>.
8288static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8289 uint32_t a = *ap;
8290 uint32_t b = *bp;
8291 return (a == b) ? 0 : (a < b) ? -1 : 1;
8292}
8293
8294
8295static void CollectElementIndices(Handle<JSObject> object,
8296 uint32_t range,
8297 List<uint32_t>* indices) {
8298 JSObject::ElementsKind kind = object->GetElementsKind();
8299 switch (kind) {
8300 case JSObject::FAST_ELEMENTS: {
8301 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8302 uint32_t length = static_cast<uint32_t>(elements->length());
8303 if (range < length) length = range;
8304 for (uint32_t i = 0; i < length; i++) {
8305 if (!elements->get(i)->IsTheHole()) {
8306 indices->Add(i);
8307 }
8308 }
8309 break;
8310 }
8311 case JSObject::DICTIONARY_ELEMENTS: {
8312 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008313 uint32_t capacity = dict->Capacity();
8314 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008315 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008316 Handle<Object> k(dict->KeyAt(j));
8317 if (dict->IsKey(*k)) {
8318 ASSERT(k->IsNumber());
8319 uint32_t index = static_cast<uint32_t>(k->Number());
8320 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008321 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008322 }
8323 }
8324 }
8325 break;
8326 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008327 default: {
8328 int dense_elements_length;
8329 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008330 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008331 dense_elements_length =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008332 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008333 break;
8334 }
8335 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8336 dense_elements_length =
8337 ExternalByteArray::cast(object->elements())->length();
8338 break;
8339 }
8340 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8341 dense_elements_length =
8342 ExternalUnsignedByteArray::cast(object->elements())->length();
8343 break;
8344 }
8345 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8346 dense_elements_length =
8347 ExternalShortArray::cast(object->elements())->length();
8348 break;
8349 }
8350 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8351 dense_elements_length =
8352 ExternalUnsignedShortArray::cast(object->elements())->length();
8353 break;
8354 }
8355 case JSObject::EXTERNAL_INT_ELEMENTS: {
8356 dense_elements_length =
8357 ExternalIntArray::cast(object->elements())->length();
8358 break;
8359 }
8360 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8361 dense_elements_length =
8362 ExternalUnsignedIntArray::cast(object->elements())->length();
8363 break;
8364 }
8365 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8366 dense_elements_length =
8367 ExternalFloatArray::cast(object->elements())->length();
8368 break;
8369 }
8370 default:
8371 UNREACHABLE();
8372 dense_elements_length = 0;
8373 break;
8374 }
8375 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8376 if (range <= length) {
8377 length = range;
8378 // We will add all indices, so we might as well clear it first
8379 // and avoid duplicates.
8380 indices->Clear();
8381 }
8382 for (uint32_t i = 0; i < length; i++) {
8383 indices->Add(i);
8384 }
8385 if (length == range) return; // All indices accounted for already.
8386 break;
8387 }
8388 }
8389
8390 Handle<Object> prototype(object->GetPrototype());
8391 if (prototype->IsJSObject()) {
8392 // The prototype will usually have no inherited element indices,
8393 // but we have to check.
8394 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8395 }
8396}
8397
8398
8399/**
8400 * A helper function that visits elements of a JSArray in numerical
8401 * order.
8402 *
8403 * The visitor argument called for each existing element in the array
8404 * with the element index and the element's value.
8405 * Afterwards it increments the base-index of the visitor by the array
8406 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008407 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008408 */
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008409static bool IterateElements(Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008410 ArrayConcatVisitor* visitor) {
8411 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8412 switch (receiver->GetElementsKind()) {
8413 case JSObject::FAST_ELEMENTS: {
8414 // Run through the elements FixedArray and use HasElement and GetElement
8415 // to check the prototype for missing elements.
8416 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8417 int fast_length = static_cast<int>(length);
8418 ASSERT(fast_length <= elements->length());
8419 for (int j = 0; j < fast_length; j++) {
8420 HandleScope loop_scope;
8421 Handle<Object> element_value(elements->get(j));
8422 if (!element_value->IsTheHole()) {
8423 visitor->visit(j, element_value);
8424 } else if (receiver->HasElement(j)) {
8425 // Call GetElement on receiver, not its prototype, or getters won't
8426 // have the correct receiver.
8427 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008428 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008429 visitor->visit(j, element_value);
8430 }
8431 }
8432 break;
8433 }
8434 case JSObject::DICTIONARY_ELEMENTS: {
8435 Handle<NumberDictionary> dict(receiver->element_dictionary());
8436 List<uint32_t> indices(dict->Capacity() / 2);
8437 // Collect all indices in the object and the prototypes less
8438 // than length. This might introduce duplicates in the indices list.
8439 CollectElementIndices(receiver, length, &indices);
8440 indices.Sort(&compareUInt32);
8441 int j = 0;
8442 int n = indices.length();
8443 while (j < n) {
8444 HandleScope loop_scope;
8445 uint32_t index = indices[j];
8446 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008447 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008448 visitor->visit(index, element);
8449 // Skip to next different index (i.e., omit duplicates).
8450 do {
8451 j++;
8452 } while (j < n && indices[j] == index);
8453 }
8454 break;
8455 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008456 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8457 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8458 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008459 for (uint32_t j = 0; j < length; j++) {
8460 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8461 visitor->visit(j, e);
8462 }
8463 break;
8464 }
8465 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8466 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8467 receiver, true, true, visitor);
8468 break;
8469 }
8470 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8471 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8472 receiver, true, true, visitor);
8473 break;
8474 }
8475 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8476 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8477 receiver, true, true, visitor);
8478 break;
8479 }
8480 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8481 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8482 receiver, true, true, visitor);
8483 break;
8484 }
8485 case JSObject::EXTERNAL_INT_ELEMENTS: {
8486 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8487 receiver, true, false, visitor);
8488 break;
8489 }
8490 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8491 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8492 receiver, true, false, visitor);
8493 break;
8494 }
8495 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8496 IterateExternalArrayElements<ExternalFloatArray, float>(
8497 receiver, false, false, visitor);
8498 break;
8499 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008500 default:
8501 UNREACHABLE();
8502 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008503 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008504 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008505 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008506}
8507
8508
8509/**
8510 * Array::concat implementation.
8511 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008512 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008513 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008514 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008515static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008516 ASSERT(args.length() == 1);
8517 HandleScope handle_scope;
8518
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008519 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8520 int argument_count = static_cast<int>(arguments->length()->Number());
8521 RUNTIME_ASSERT(arguments->HasFastElements());
8522 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008523
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008524 // Pass 1: estimate the length and number of elements of the result.
8525 // The actual length can be larger if any of the arguments have getters
8526 // that mutate other arguments (but will otherwise be precise).
8527 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008528
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008529 uint32_t estimate_result_length = 0;
8530 uint32_t estimate_nof_elements = 0;
8531 {
8532 for (int i = 0; i < argument_count; i++) {
8533 HandleScope loop_scope;
8534 Handle<Object> obj(elements->get(i));
8535 uint32_t length_estimate;
8536 uint32_t element_estimate;
8537 if (obj->IsJSArray()) {
8538 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8539 length_estimate =
8540 static_cast<uint32_t>(array->length()->Number());
8541 element_estimate =
8542 EstimateElementCount(array);
8543 } else {
8544 length_estimate = 1;
8545 element_estimate = 1;
8546 }
8547 // Avoid overflows by capping at kMaxElementCount.
8548 if (JSObject::kMaxElementCount - estimate_result_length <
8549 length_estimate) {
8550 estimate_result_length = JSObject::kMaxElementCount;
8551 } else {
8552 estimate_result_length += length_estimate;
8553 }
8554 if (JSObject::kMaxElementCount - estimate_nof_elements <
8555 element_estimate) {
8556 estimate_nof_elements = JSObject::kMaxElementCount;
8557 } else {
8558 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008559 }
8560 }
8561 }
8562
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008563 // If estimated number of elements is more than half of length, a
8564 // fixed array (fast case) is more time and space-efficient than a
8565 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008566 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008567
8568 Handle<FixedArray> storage;
8569 if (fast_case) {
8570 // The backing storage array must have non-existing elements to
8571 // preserve holes across concat operations.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008572 storage = Factory::NewFixedArrayWithHoles(estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008573 } else {
8574 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8575 uint32_t at_least_space_for = estimate_nof_elements +
8576 (estimate_nof_elements >> 2);
8577 storage = Handle<FixedArray>::cast(
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008578 Factory::NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008579 }
8580
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008581 ArrayConcatVisitor visitor(storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008582
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008583 for (int i = 0; i < argument_count; i++) {
8584 Handle<Object> obj(elements->get(i));
8585 if (obj->IsJSArray()) {
8586 Handle<JSArray> array = Handle<JSArray>::cast(obj);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008587 if (!IterateElements(array, &visitor)) {
8588 return Failure::Exception();
8589 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008590 } else {
8591 visitor.visit(0, obj);
8592 visitor.increase_index_offset(1);
8593 }
8594 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008595
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008596 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008597}
8598
8599
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008600// This will not allocate (flatten the string), but it may run
8601// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008602static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008603 NoHandleAllocation ha;
8604 ASSERT(args.length() == 1);
8605
8606 CONVERT_CHECKED(String, string, args[0]);
8607 StringInputBuffer buffer(string);
8608 while (buffer.has_more()) {
8609 uint16_t character = buffer.GetNext();
8610 PrintF("%c", character);
8611 }
8612 return string;
8613}
8614
ager@chromium.org5ec48922009-05-05 07:25:34 +00008615// Moves all own elements of an object, that are below a limit, to positions
8616// starting at zero. All undefined values are placed after non-undefined values,
8617// and are followed by non-existing element. Does not change the length
8618// property.
8619// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008620static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008621 ASSERT(args.length() == 2);
8622 CONVERT_CHECKED(JSObject, object, args[0]);
8623 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8624 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008625}
8626
8627
8628// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008629static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008630 ASSERT(args.length() == 2);
8631 CONVERT_CHECKED(JSArray, from, args[0]);
8632 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008633 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008634 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008635 if (new_elements->map() == Heap::fixed_array_map() ||
8636 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008637 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008638 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008639 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008640 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008641 Object* new_map;
8642 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008643 to->set_map(Map::cast(new_map));
8644 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008645 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008646 Object* obj;
8647 { MaybeObject* maybe_obj = from->ResetElements();
8648 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8649 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008650 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008651 return to;
8652}
8653
8654
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008655// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008656static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008657 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008658 CONVERT_CHECKED(JSObject, object, args[0]);
8659 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008660 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008661 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008662 } else if (object->IsJSArray()) {
8663 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008664 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008665 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008666 }
8667}
8668
8669
lrn@chromium.org303ada72010-10-27 09:33:13 +00008670static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008671 HandleScope handle_scope;
8672
8673 ASSERT_EQ(3, args.length());
8674
ager@chromium.orgac091b72010-05-05 07:34:42 +00008675 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008676 Handle<Object> key1 = args.at<Object>(1);
8677 Handle<Object> key2 = args.at<Object>(2);
8678
8679 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008680 if (!key1->ToArrayIndex(&index1)
8681 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008682 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008683 }
8684
ager@chromium.orgac091b72010-05-05 07:34:42 +00008685 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8686 Handle<Object> tmp1 = GetElement(jsobject, index1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008687 RETURN_IF_EMPTY_HANDLE(tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008688 Handle<Object> tmp2 = GetElement(jsobject, index2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008689 RETURN_IF_EMPTY_HANDLE(tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008690
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008691 RETURN_IF_EMPTY_HANDLE(SetElement(jsobject, index1, tmp2, kStrictMode));
8692 RETURN_IF_EMPTY_HANDLE(SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00008693
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008694 return Heap::undefined_value();
8695}
8696
8697
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008698// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008699// might have elements. Can either return keys (positive integers) or
8700// intervals (pair of a negative integer (-start-1) followed by a
8701// positive (length)) or undefined values.
8702// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008703static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008704 ASSERT(args.length() == 2);
8705 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008706 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008707 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008708 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008709 // Create an array and get all the keys into it, then remove all the
8710 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008711 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008712 int keys_length = keys->length();
8713 for (int i = 0; i < keys_length; i++) {
8714 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008715 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008716 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008717 // Zap invalid keys.
8718 keys->set_undefined(i);
8719 }
8720 }
8721 return *Factory::NewJSArrayWithElements(keys);
8722 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008723 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008724 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8725 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008726 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008727 uint32_t actual_length =
8728 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008729 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008730 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008731 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008732 single_interval->set(1, *length_object);
8733 return *Factory::NewJSArrayWithElements(single_interval);
8734 }
8735}
8736
8737
8738// DefineAccessor takes an optional final argument which is the
8739// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8740// to the way accessors are implemented, it is set for both the getter
8741// and setter on the first call to DefineAccessor and ignored on
8742// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008743static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008744 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8745 // Compute attributes.
8746 PropertyAttributes attributes = NONE;
8747 if (args.length() == 5) {
8748 CONVERT_CHECKED(Smi, attrs, args[4]);
8749 int value = attrs->value();
8750 // Only attribute bits should be set.
8751 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8752 attributes = static_cast<PropertyAttributes>(value);
8753 }
8754
8755 CONVERT_CHECKED(JSObject, obj, args[0]);
8756 CONVERT_CHECKED(String, name, args[1]);
8757 CONVERT_CHECKED(Smi, flag, args[2]);
8758 CONVERT_CHECKED(JSFunction, fun, args[3]);
8759 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8760}
8761
8762
lrn@chromium.org303ada72010-10-27 09:33:13 +00008763static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008764 ASSERT(args.length() == 3);
8765 CONVERT_CHECKED(JSObject, obj, args[0]);
8766 CONVERT_CHECKED(String, name, args[1]);
8767 CONVERT_CHECKED(Smi, flag, args[2]);
8768 return obj->LookupAccessor(name, flag->value() == 0);
8769}
8770
8771
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008772#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008773static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008774 ASSERT(args.length() == 0);
8775 return Execution::DebugBreakHelper();
8776}
8777
8778
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008779// Helper functions for wrapping and unwrapping stack frame ids.
8780static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008781 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008782 return Smi::FromInt(id >> 2);
8783}
8784
8785
8786static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8787 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8788}
8789
8790
8791// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008792// args[0]: debug event listener function to set or null or undefined for
8793// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008794// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008795static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008796 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008797 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8798 args[0]->IsUndefined() ||
8799 args[0]->IsNull());
8800 Handle<Object> callback = args.at<Object>(0);
8801 Handle<Object> data = args.at<Object>(1);
8802 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008803
8804 return Heap::undefined_value();
8805}
8806
8807
lrn@chromium.org303ada72010-10-27 09:33:13 +00008808static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008809 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008810 StackGuard::DebugBreak();
8811 return Heap::undefined_value();
8812}
8813
8814
lrn@chromium.org303ada72010-10-27 09:33:13 +00008815static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8816 LookupResult* result,
8817 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008818 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008819 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008820 case NORMAL:
8821 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008822 if (value->IsTheHole()) {
8823 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008824 }
8825 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008826 case FIELD:
8827 value =
8828 JSObject::cast(
8829 result->holder())->FastPropertyAt(result->GetFieldIndex());
8830 if (value->IsTheHole()) {
8831 return Heap::undefined_value();
8832 }
8833 return value;
8834 case CONSTANT_FUNCTION:
8835 return result->GetConstantFunction();
8836 case CALLBACKS: {
8837 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008838 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008839 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008840 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008841 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008842 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008843 ASSERT(maybe_value->IsException());
8844 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008845 Top::clear_pending_exception();
8846 if (caught_exception != NULL) {
8847 *caught_exception = true;
8848 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008849 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008850 }
8851 return value;
8852 } else {
8853 return Heap::undefined_value();
8854 }
8855 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008856 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008857 case MAP_TRANSITION:
8858 case CONSTANT_TRANSITION:
8859 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008860 return Heap::undefined_value();
8861 default:
8862 UNREACHABLE();
8863 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008864 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008865 return Heap::undefined_value();
8866}
8867
8868
ager@chromium.org32912102009-01-16 10:38:43 +00008869// Get debugger related details for an object property.
8870// args[0]: object holding property
8871// args[1]: name of the property
8872//
8873// The array returned contains the following information:
8874// 0: Property value
8875// 1: Property details
8876// 2: Property value is exception
8877// 3: Getter function if defined
8878// 4: Setter function if defined
8879// Items 2-4 are only filled if the property has either a getter or a setter
8880// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008881static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008882 HandleScope scope;
8883
8884 ASSERT(args.length() == 2);
8885
8886 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8887 CONVERT_ARG_CHECKED(String, name, 1);
8888
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008889 // Make sure to set the current context to the context before the debugger was
8890 // entered (if the debugger is entered). The reason for switching context here
8891 // is that for some property lookups (accessors and interceptors) callbacks
8892 // into the embedding application can occour, and the embedding application
8893 // could have the assumption that its own global context is the current
8894 // context and not some internal debugger context.
8895 SaveContext save;
8896 if (Debug::InDebugger()) {
8897 Top::set_context(*Debug::debugger_entry()->GetContext());
8898 }
8899
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008900 // Skip the global proxy as it has no properties and always delegates to the
8901 // real global object.
8902 if (obj->IsJSGlobalProxy()) {
8903 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8904 }
8905
8906
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008907 // Check if the name is trivially convertible to an index and get the element
8908 // if so.
8909 uint32_t index;
8910 if (name->AsArrayIndex(&index)) {
8911 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008912 Object* element_or_char;
8913 { MaybeObject* maybe_element_or_char =
8914 Runtime::GetElementOrCharAt(obj, index);
8915 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8916 return maybe_element_or_char;
8917 }
8918 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008919 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008920 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8921 return *Factory::NewJSArrayWithElements(details);
8922 }
8923
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008924 // Find the number of objects making up this.
8925 int length = LocalPrototypeChainLength(*obj);
8926
8927 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008928 Handle<JSObject> jsproto = obj;
8929 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008930 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008931 jsproto->LocalLookup(*name, &result);
8932 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008933 // LookupResult is not GC safe as it holds raw object pointers.
8934 // GC can happen later in this code so put the required fields into
8935 // local variables using handles when required for later use.
8936 PropertyType result_type = result.type();
8937 Handle<Object> result_callback_obj;
8938 if (result_type == CALLBACKS) {
8939 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8940 }
8941 Smi* property_details = result.GetPropertyDetails().AsSmi();
8942 // DebugLookupResultValue can cause GC so details from LookupResult needs
8943 // to be copied to handles before this.
8944 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008945 Object* raw_value;
8946 { MaybeObject* maybe_raw_value =
8947 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8948 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8949 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008950 Handle<Object> value(raw_value);
8951
8952 // If the callback object is a fixed array then it contains JavaScript
8953 // getter and/or setter.
8954 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8955 result_callback_obj->IsFixedArray();
8956 Handle<FixedArray> details =
8957 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8958 details->set(0, *value);
8959 details->set(1, property_details);
8960 if (hasJavaScriptAccessors) {
8961 details->set(2,
8962 caught_exception ? Heap::true_value()
8963 : Heap::false_value());
8964 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8965 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8966 }
8967
8968 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008969 }
8970 if (i < length - 1) {
8971 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8972 }
8973 }
8974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008975 return Heap::undefined_value();
8976}
8977
8978
lrn@chromium.org303ada72010-10-27 09:33:13 +00008979static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008980 HandleScope scope;
8981
8982 ASSERT(args.length() == 2);
8983
8984 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8985 CONVERT_ARG_CHECKED(String, name, 1);
8986
8987 LookupResult result;
8988 obj->Lookup(*name, &result);
8989 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008990 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008991 }
8992 return Heap::undefined_value();
8993}
8994
8995
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008996// Return the property type calculated from the property details.
8997// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008998static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008999 ASSERT(args.length() == 1);
9000 CONVERT_CHECKED(Smi, details, args[0]);
9001 PropertyType type = PropertyDetails(details).type();
9002 return Smi::FromInt(static_cast<int>(type));
9003}
9004
9005
9006// Return the property attribute calculated from the property details.
9007// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009008static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009009 ASSERT(args.length() == 1);
9010 CONVERT_CHECKED(Smi, details, args[0]);
9011 PropertyAttributes attributes = PropertyDetails(details).attributes();
9012 return Smi::FromInt(static_cast<int>(attributes));
9013}
9014
9015
9016// Return the property insertion index calculated from the property details.
9017// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009018static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019 ASSERT(args.length() == 1);
9020 CONVERT_CHECKED(Smi, details, args[0]);
9021 int index = PropertyDetails(details).index();
9022 return Smi::FromInt(index);
9023}
9024
9025
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009026// Return property value from named interceptor.
9027// args[0]: object
9028// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00009029static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009030 HandleScope scope;
9031 ASSERT(args.length() == 2);
9032 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9033 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9034 CONVERT_ARG_CHECKED(String, name, 1);
9035
9036 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009037 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009038}
9039
9040
9041// Return element value from indexed interceptor.
9042// args[0]: object
9043// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00009044static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
9045 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009046 HandleScope scope;
9047 ASSERT(args.length() == 2);
9048 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9049 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9050 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9051
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009052 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053}
9054
9055
lrn@chromium.org303ada72010-10-27 09:33:13 +00009056static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009057 ASSERT(args.length() >= 1);
9058 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009059 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009060 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009061 return Top::Throw(Heap::illegal_execution_state_symbol());
9062 }
9063
9064 return Heap::true_value();
9065}
9066
9067
lrn@chromium.org303ada72010-10-27 09:33:13 +00009068static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009069 HandleScope scope;
9070 ASSERT(args.length() == 1);
9071
9072 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009073 Object* result;
9074 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9075 if (!maybe_result->ToObject(&result)) return maybe_result;
9076 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009077
9078 // Count all frames which are relevant to debugging stack trace.
9079 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009080 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009081 if (id == StackFrame::NO_ID) {
9082 // If there is no JavaScript stack frame count is 0.
9083 return Smi::FromInt(0);
9084 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009085 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
9086 return Smi::FromInt(n);
9087}
9088
9089
9090static const int kFrameDetailsFrameIdIndex = 0;
9091static const int kFrameDetailsReceiverIndex = 1;
9092static const int kFrameDetailsFunctionIndex = 2;
9093static const int kFrameDetailsArgumentCountIndex = 3;
9094static const int kFrameDetailsLocalCountIndex = 4;
9095static const int kFrameDetailsSourcePositionIndex = 5;
9096static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009097static const int kFrameDetailsAtReturnIndex = 7;
9098static const int kFrameDetailsDebuggerFrameIndex = 8;
9099static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009100
9101// Return an array with frame details
9102// args[0]: number: break id
9103// args[1]: number: frame index
9104//
9105// The array returned contains the following information:
9106// 0: Frame id
9107// 1: Receiver
9108// 2: Function
9109// 3: Argument count
9110// 4: Local count
9111// 5: Source position
9112// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009113// 7: Is at return
9114// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009115// Arguments name, value
9116// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009117// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00009118static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119 HandleScope scope;
9120 ASSERT(args.length() == 2);
9121
9122 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009123 Object* check;
9124 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9125 if (!maybe_check->ToObject(&check)) return maybe_check;
9126 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009127 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9128
9129 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009130 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009131 if (id == StackFrame::NO_ID) {
9132 // If there are no JavaScript stack frames return undefined.
9133 return Heap::undefined_value();
9134 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009135 int count = 0;
9136 JavaScriptFrameIterator it(id);
9137 for (; !it.done(); it.Advance()) {
9138 if (count == index) break;
9139 count++;
9140 }
9141 if (it.done()) return Heap::undefined_value();
9142
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009143 bool is_optimized_frame =
9144 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
9145
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009146 // Traverse the saved contexts chain to find the active context for the
9147 // selected frame.
9148 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009149 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009150 save = save->prev();
9151 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009152 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009153
9154 // Get the frame id.
9155 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
9156
9157 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00009158 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159
9160 // Check for constructor frame.
9161 bool constructor = it.frame()->IsConstructor();
9162
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009163 // Get scope info and read from it for local variable information.
9164 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009165 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009166 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009167
9168 // Get the context.
9169 Handle<Context> context(Context::cast(it.frame()->context()));
9170
9171 // Get the locals names and values into a temporary array.
9172 //
9173 // TODO(1240907): Hide compiler-introduced stack variables
9174 // (e.g. .result)? For users of the debugger, they will probably be
9175 // confusing.
9176 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009177
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009178 // Fill in the names of the locals.
9179 for (int i = 0; i < info.NumberOfLocals(); i++) {
9180 locals->set(i * 2, *info.LocalName(i));
9181 }
9182
9183 // Fill in the values of the locals.
9184 for (int i = 0; i < info.NumberOfLocals(); i++) {
9185 if (is_optimized_frame) {
9186 // If we are inspecting an optimized frame use undefined as the
9187 // value for all locals.
9188 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009189 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009190 // for locals in optimized frames.
9191 locals->set(i * 2 + 1, Heap::undefined_value());
9192 } else if (i < info.number_of_stack_slots()) {
9193 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009194 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9195 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009196 // Traverse the context chain to the function context as all local
9197 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009198 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009199 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009200 context = Handle<Context>(context->previous());
9201 }
9202 ASSERT(context->is_function_context());
9203 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009204 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009205 }
9206 }
9207
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009208 // Check whether this frame is positioned at return. If not top
9209 // frame or if the frame is optimized it cannot be at a return.
9210 bool at_return = false;
9211 if (!is_optimized_frame && index == 0) {
9212 at_return = Debug::IsBreakAtReturn(it.frame());
9213 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009214
9215 // If positioned just before return find the value to be returned and add it
9216 // to the frame information.
9217 Handle<Object> return_value = Factory::undefined_value();
9218 if (at_return) {
9219 StackFrameIterator it2;
9220 Address internal_frame_sp = NULL;
9221 while (!it2.done()) {
9222 if (it2.frame()->is_internal()) {
9223 internal_frame_sp = it2.frame()->sp();
9224 } else {
9225 if (it2.frame()->is_java_script()) {
9226 if (it2.frame()->id() == it.frame()->id()) {
9227 // The internal frame just before the JavaScript frame contains the
9228 // value to return on top. A debug break at return will create an
9229 // internal frame to store the return value (eax/rax/r0) before
9230 // entering the debug break exit frame.
9231 if (internal_frame_sp != NULL) {
9232 return_value =
9233 Handle<Object>(Memory::Object_at(internal_frame_sp));
9234 break;
9235 }
9236 }
9237 }
9238
9239 // Indicate that the previous frame was not an internal frame.
9240 internal_frame_sp = NULL;
9241 }
9242 it2.Advance();
9243 }
9244 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009245
9246 // Now advance to the arguments adapter frame (if any). It contains all
9247 // the provided parameters whereas the function frame always have the number
9248 // of arguments matching the functions parameters. The rest of the
9249 // information (except for what is collected above) is the same.
9250 it.AdvanceToArgumentsFrame();
9251
9252 // Find the number of arguments to fill. At least fill the number of
9253 // parameters for the function and fill more if more parameters are provided.
9254 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009255 if (argument_count < it.frame()->ComputeParametersCount()) {
9256 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009257 }
9258
9259 // Calculate the size of the result.
9260 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009261 2 * (argument_count + info.NumberOfLocals()) +
9262 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009263 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9264
9265 // Add the frame id.
9266 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9267
9268 // Add the function (same as in function frame).
9269 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9270
9271 // Add the arguments count.
9272 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9273
9274 // Add the locals count
9275 details->set(kFrameDetailsLocalCountIndex,
9276 Smi::FromInt(info.NumberOfLocals()));
9277
9278 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009279 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009280 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9281 } else {
9282 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
9283 }
9284
9285 // Add the constructor information.
9286 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
9287
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009288 // Add the at return information.
9289 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
9290
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009291 // Add information on whether this frame is invoked in the debugger context.
9292 details->set(kFrameDetailsDebuggerFrameIndex,
9293 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
9294
9295 // Fill the dynamic part.
9296 int details_index = kFrameDetailsFirstDynamicIndex;
9297
9298 // Add arguments name and value.
9299 for (int i = 0; i < argument_count; i++) {
9300 // Name of the argument.
9301 if (i < info.number_of_parameters()) {
9302 details->set(details_index++, *info.parameter_name(i));
9303 } else {
9304 details->set(details_index++, Heap::undefined_value());
9305 }
9306
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009307 // Parameter value. If we are inspecting an optimized frame, use
9308 // undefined as the value.
9309 //
9310 // TODO(3141533): We should be able to get the actual parameter
9311 // value for optimized frames.
9312 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009313 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009314 details->set(details_index++, it.frame()->GetParameter(i));
9315 } else {
9316 details->set(details_index++, Heap::undefined_value());
9317 }
9318 }
9319
9320 // Add locals name and value from the temporary copy from the function frame.
9321 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9322 details->set(details_index++, locals->get(i));
9323 }
9324
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009325 // Add the value being returned.
9326 if (at_return) {
9327 details->set(details_index++, *return_value);
9328 }
9329
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009330 // Add the receiver (same as in function frame).
9331 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9332 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
9333 Handle<Object> receiver(it.frame()->receiver());
9334 if (!receiver->IsJSObject()) {
9335 // If the receiver is NOT a JSObject we have hit an optimization
9336 // where a value object is not converted into a wrapped JS objects.
9337 // To hide this optimization from the debugger, we wrap the receiver
9338 // by creating correct wrapper object based on the calling frame's
9339 // global context.
9340 it.Advance();
9341 Handle<Context> calling_frames_global_context(
9342 Context::cast(Context::cast(it.frame()->context())->global_context()));
9343 receiver = Factory::ToObject(receiver, calling_frames_global_context);
9344 }
9345 details->set(kFrameDetailsReceiverIndex, *receiver);
9346
9347 ASSERT_EQ(details_size, details_index);
9348 return *Factory::NewJSArrayWithElements(details);
9349}
9350
9351
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009352// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009353static bool CopyContextLocalsToScopeObject(
ager@chromium.orgb5737492010-07-15 09:29:43 +00009354 Handle<SerializedScopeInfo> serialized_scope_info,
9355 ScopeInfo<>& scope_info,
9356 Handle<Context> context,
9357 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009358 // Fill all context locals to the context extension.
9359 for (int i = Context::MIN_CONTEXT_SLOTS;
9360 i < scope_info.number_of_context_slots();
9361 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009362 int context_index = serialized_scope_info->ContextSlotIndex(
9363 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009364
9365 // Don't include the arguments shadow (.arguments) context variable.
9366 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009367 RETURN_IF_EMPTY_HANDLE_VALUE(
9368 SetProperty(scope_object,
9369 scope_info.context_slot_name(i),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009370 Handle<Object>(context->get(context_index)),
9371 NONE,
9372 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009373 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009374 }
9375 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009376
9377 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009378}
9379
9380
9381// Create a plain JSObject which materializes the local scope for the specified
9382// frame.
9383static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
9384 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009385 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009386 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9387 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009388
9389 // Allocate and initialize a JSObject with all the arguments, stack locals
9390 // heap locals and extension properties of the debugged function.
9391 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
9392
9393 // First fill all parameters.
9394 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009395 RETURN_IF_EMPTY_HANDLE_VALUE(
9396 SetProperty(local_scope,
9397 scope_info.parameter_name(i),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009398 Handle<Object>(frame->GetParameter(i)),
9399 NONE,
9400 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009401 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009402 }
9403
9404 // Second fill all stack locals.
9405 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009406 RETURN_IF_EMPTY_HANDLE_VALUE(
9407 SetProperty(local_scope,
9408 scope_info.stack_slot_name(i),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009409 Handle<Object>(frame->GetExpression(i)),
9410 NONE,
9411 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009412 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009413 }
9414
9415 // Third fill all context locals.
9416 Handle<Context> frame_context(Context::cast(frame->context()));
9417 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009418 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9419 function_context, local_scope)) {
9420 return Handle<JSObject>();
9421 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009422
9423 // Finally copy any properties from the function context extension. This will
9424 // be variables introduced by eval.
9425 if (function_context->closure() == *function) {
9426 if (function_context->has_extension() &&
9427 !function_context->IsGlobalContext()) {
9428 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009429 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009430 for (int i = 0; i < keys->length(); i++) {
9431 // Names of variables introduced by eval are strings.
9432 ASSERT(keys->get(i)->IsString());
9433 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009434 RETURN_IF_EMPTY_HANDLE_VALUE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009435 SetProperty(local_scope,
9436 key,
9437 GetProperty(ext, key),
9438 NONE,
9439 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009440 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009441 }
9442 }
9443 }
9444 return local_scope;
9445}
9446
9447
9448// Create a plain JSObject which materializes the closure content for the
9449// context.
9450static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
9451 ASSERT(context->is_function_context());
9452
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009453 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009454 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9455 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009456
9457 // Allocate and initialize a JSObject with all the content of theis function
9458 // closure.
9459 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
9460
9461 // Check whether the arguments shadow object exists.
9462 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00009463 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
9464 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009465 if (arguments_shadow_index >= 0) {
9466 // In this case all the arguments are available in the arguments shadow
9467 // object.
9468 Handle<JSObject> arguments_shadow(
9469 JSObject::cast(context->get(arguments_shadow_index)));
9470 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009471 // We don't expect exception-throwing getters on the arguments shadow.
9472 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009473 RETURN_IF_EMPTY_HANDLE_VALUE(
9474 SetProperty(closure_scope,
9475 scope_info.parameter_name(i),
9476 Handle<Object>(element),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009477 NONE,
9478 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009479 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009480 }
9481 }
9482
9483 // Fill all context locals to the context extension.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009484 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9485 context, closure_scope)) {
9486 return Handle<JSObject>();
9487 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009488
9489 // Finally copy any properties from the function context extension. This will
9490 // be variables introduced by eval.
9491 if (context->has_extension()) {
9492 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009493 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009494 for (int i = 0; i < keys->length(); i++) {
9495 // Names of variables introduced by eval are strings.
9496 ASSERT(keys->get(i)->IsString());
9497 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009498 RETURN_IF_EMPTY_HANDLE_VALUE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009499 SetProperty(closure_scope,
9500 key,
9501 GetProperty(ext, key),
9502 NONE,
9503 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009504 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009505 }
9506 }
9507
9508 return closure_scope;
9509}
9510
9511
9512// Iterate over the actual scopes visible from a stack frame. All scopes are
9513// backed by an actual context except the local scope, which is inserted
9514// "artifically" in the context chain.
9515class ScopeIterator {
9516 public:
9517 enum ScopeType {
9518 ScopeTypeGlobal = 0,
9519 ScopeTypeLocal,
9520 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009521 ScopeTypeClosure,
9522 // Every catch block contains an implicit with block (its parameter is
9523 // a JSContextExtensionObject) that extends current scope with a variable
9524 // holding exception object. Such with blocks are treated as scopes of their
9525 // own type.
9526 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009527 };
9528
9529 explicit ScopeIterator(JavaScriptFrame* frame)
9530 : frame_(frame),
9531 function_(JSFunction::cast(frame->function())),
9532 context_(Context::cast(frame->context())),
9533 local_done_(false),
9534 at_local_(false) {
9535
9536 // Check whether the first scope is actually a local scope.
9537 if (context_->IsGlobalContext()) {
9538 // If there is a stack slot for .result then this local scope has been
9539 // created for evaluating top level code and it is not a real local scope.
9540 // Checking for the existence of .result seems fragile, but the scope info
9541 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009542 int index = function_->shared()->scope_info()->
9543 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009544 at_local_ = index < 0;
9545 } else if (context_->is_function_context()) {
9546 at_local_ = true;
9547 }
9548 }
9549
9550 // More scopes?
9551 bool Done() { return context_.is_null(); }
9552
9553 // Move to the next scope.
9554 void Next() {
9555 // If at a local scope mark the local scope as passed.
9556 if (at_local_) {
9557 at_local_ = false;
9558 local_done_ = true;
9559
9560 // If the current context is not associated with the local scope the
9561 // current context is the next real scope, so don't move to the next
9562 // context in this case.
9563 if (context_->closure() != *function_) {
9564 return;
9565 }
9566 }
9567
9568 // The global scope is always the last in the chain.
9569 if (context_->IsGlobalContext()) {
9570 context_ = Handle<Context>();
9571 return;
9572 }
9573
9574 // Move to the next context.
9575 if (context_->is_function_context()) {
9576 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9577 } else {
9578 context_ = Handle<Context>(context_->previous());
9579 }
9580
9581 // If passing the local scope indicate that the current scope is now the
9582 // local scope.
9583 if (!local_done_ &&
9584 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9585 at_local_ = true;
9586 }
9587 }
9588
9589 // Return the type of the current scope.
9590 int Type() {
9591 if (at_local_) {
9592 return ScopeTypeLocal;
9593 }
9594 if (context_->IsGlobalContext()) {
9595 ASSERT(context_->global()->IsGlobalObject());
9596 return ScopeTypeGlobal;
9597 }
9598 if (context_->is_function_context()) {
9599 return ScopeTypeClosure;
9600 }
9601 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009602 // Current scope is either an explicit with statement or a with statement
9603 // implicitely generated for a catch block.
9604 // If the extension object here is a JSContextExtensionObject then
9605 // current with statement is one frome a catch block otherwise it's a
9606 // regular with statement.
9607 if (context_->extension()->IsJSContextExtensionObject()) {
9608 return ScopeTypeCatch;
9609 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009610 return ScopeTypeWith;
9611 }
9612
9613 // Return the JavaScript object with the content of the current scope.
9614 Handle<JSObject> ScopeObject() {
9615 switch (Type()) {
9616 case ScopeIterator::ScopeTypeGlobal:
9617 return Handle<JSObject>(CurrentContext()->global());
9618 break;
9619 case ScopeIterator::ScopeTypeLocal:
9620 // Materialize the content of the local scope into a JSObject.
9621 return MaterializeLocalScope(frame_);
9622 break;
9623 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009624 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009625 // Return the with object.
9626 return Handle<JSObject>(CurrentContext()->extension());
9627 break;
9628 case ScopeIterator::ScopeTypeClosure:
9629 // Materialize the content of the closure scope into a JSObject.
9630 return MaterializeClosure(CurrentContext());
9631 break;
9632 }
9633 UNREACHABLE();
9634 return Handle<JSObject>();
9635 }
9636
9637 // Return the context for this scope. For the local context there might not
9638 // be an actual context.
9639 Handle<Context> CurrentContext() {
9640 if (at_local_ && context_->closure() != *function_) {
9641 return Handle<Context>();
9642 }
9643 return context_;
9644 }
9645
9646#ifdef DEBUG
9647 // Debug print of the content of the current scope.
9648 void DebugPrint() {
9649 switch (Type()) {
9650 case ScopeIterator::ScopeTypeGlobal:
9651 PrintF("Global:\n");
9652 CurrentContext()->Print();
9653 break;
9654
9655 case ScopeIterator::ScopeTypeLocal: {
9656 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009657 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009658 scope_info.Print();
9659 if (!CurrentContext().is_null()) {
9660 CurrentContext()->Print();
9661 if (CurrentContext()->has_extension()) {
9662 Handle<JSObject> extension =
9663 Handle<JSObject>(CurrentContext()->extension());
9664 if (extension->IsJSContextExtensionObject()) {
9665 extension->Print();
9666 }
9667 }
9668 }
9669 break;
9670 }
9671
9672 case ScopeIterator::ScopeTypeWith: {
9673 PrintF("With:\n");
9674 Handle<JSObject> extension =
9675 Handle<JSObject>(CurrentContext()->extension());
9676 extension->Print();
9677 break;
9678 }
9679
ager@chromium.orga1645e22009-09-09 19:27:10 +00009680 case ScopeIterator::ScopeTypeCatch: {
9681 PrintF("Catch:\n");
9682 Handle<JSObject> extension =
9683 Handle<JSObject>(CurrentContext()->extension());
9684 extension->Print();
9685 break;
9686 }
9687
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009688 case ScopeIterator::ScopeTypeClosure: {
9689 PrintF("Closure:\n");
9690 CurrentContext()->Print();
9691 if (CurrentContext()->has_extension()) {
9692 Handle<JSObject> extension =
9693 Handle<JSObject>(CurrentContext()->extension());
9694 if (extension->IsJSContextExtensionObject()) {
9695 extension->Print();
9696 }
9697 }
9698 break;
9699 }
9700
9701 default:
9702 UNREACHABLE();
9703 }
9704 PrintF("\n");
9705 }
9706#endif
9707
9708 private:
9709 JavaScriptFrame* frame_;
9710 Handle<JSFunction> function_;
9711 Handle<Context> context_;
9712 bool local_done_;
9713 bool at_local_;
9714
9715 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9716};
9717
9718
lrn@chromium.org303ada72010-10-27 09:33:13 +00009719static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009720 HandleScope scope;
9721 ASSERT(args.length() == 2);
9722
9723 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009724 Object* check;
9725 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9726 if (!maybe_check->ToObject(&check)) return maybe_check;
9727 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009728 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9729
9730 // Get the frame where the debugging is performed.
9731 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9732 JavaScriptFrameIterator it(id);
9733 JavaScriptFrame* frame = it.frame();
9734
9735 // Count the visible scopes.
9736 int n = 0;
9737 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9738 n++;
9739 }
9740
9741 return Smi::FromInt(n);
9742}
9743
9744
9745static const int kScopeDetailsTypeIndex = 0;
9746static const int kScopeDetailsObjectIndex = 1;
9747static const int kScopeDetailsSize = 2;
9748
9749// Return an array with scope details
9750// args[0]: number: break id
9751// args[1]: number: frame index
9752// args[2]: number: scope index
9753//
9754// The array returned contains the following information:
9755// 0: Scope type
9756// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009757static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009758 HandleScope scope;
9759 ASSERT(args.length() == 3);
9760
9761 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009762 Object* check;
9763 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9764 if (!maybe_check->ToObject(&check)) return maybe_check;
9765 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009766 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9767 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9768
9769 // Get the frame where the debugging is performed.
9770 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9771 JavaScriptFrameIterator frame_it(id);
9772 JavaScriptFrame* frame = frame_it.frame();
9773
9774 // Find the requested scope.
9775 int n = 0;
9776 ScopeIterator it(frame);
9777 for (; !it.Done() && n < index; it.Next()) {
9778 n++;
9779 }
9780 if (it.Done()) {
9781 return Heap::undefined_value();
9782 }
9783
9784 // Calculate the size of the result.
9785 int details_size = kScopeDetailsSize;
9786 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9787
9788 // Fill in scope details.
9789 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009790 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009791 RETURN_IF_EMPTY_HANDLE(scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009792 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009793
9794 return *Factory::NewJSArrayWithElements(details);
9795}
9796
9797
lrn@chromium.org303ada72010-10-27 09:33:13 +00009798static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009799 HandleScope scope;
9800 ASSERT(args.length() == 0);
9801
9802#ifdef DEBUG
9803 // Print the scopes for the top frame.
9804 StackFrameLocator locator;
9805 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9806 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9807 it.DebugPrint();
9808 }
9809#endif
9810 return Heap::undefined_value();
9811}
9812
9813
lrn@chromium.org303ada72010-10-27 09:33:13 +00009814static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009815 HandleScope scope;
9816 ASSERT(args.length() == 1);
9817
9818 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009819 Object* result;
9820 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9821 if (!maybe_result->ToObject(&result)) return maybe_result;
9822 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009823
9824 // Count all archived V8 threads.
9825 int n = 0;
9826 for (ThreadState* thread = ThreadState::FirstInUse();
9827 thread != NULL;
9828 thread = thread->Next()) {
9829 n++;
9830 }
9831
9832 // Total number of threads is current thread and archived threads.
9833 return Smi::FromInt(n + 1);
9834}
9835
9836
9837static const int kThreadDetailsCurrentThreadIndex = 0;
9838static const int kThreadDetailsThreadIdIndex = 1;
9839static const int kThreadDetailsSize = 2;
9840
9841// Return an array with thread details
9842// args[0]: number: break id
9843// args[1]: number: thread index
9844//
9845// The array returned contains the following information:
9846// 0: Is current thread?
9847// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009848static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009849 HandleScope scope;
9850 ASSERT(args.length() == 2);
9851
9852 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009853 Object* check;
9854 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9855 if (!maybe_check->ToObject(&check)) return maybe_check;
9856 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009857 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9858
9859 // Allocate array for result.
9860 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9861
9862 // Thread index 0 is current thread.
9863 if (index == 0) {
9864 // Fill the details.
9865 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9866 details->set(kThreadDetailsThreadIdIndex,
9867 Smi::FromInt(ThreadManager::CurrentId()));
9868 } else {
9869 // Find the thread with the requested index.
9870 int n = 1;
9871 ThreadState* thread = ThreadState::FirstInUse();
9872 while (index != n && thread != NULL) {
9873 thread = thread->Next();
9874 n++;
9875 }
9876 if (thread == NULL) {
9877 return Heap::undefined_value();
9878 }
9879
9880 // Fill the details.
9881 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9882 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9883 }
9884
9885 // Convert to JS array and return.
9886 return *Factory::NewJSArrayWithElements(details);
9887}
9888
9889
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009890// Sets the disable break state
9891// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009892static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009893 HandleScope scope;
9894 ASSERT(args.length() == 1);
9895 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9896 Debug::set_disable_break(disable_break);
9897 return Heap::undefined_value();
9898}
9899
9900
lrn@chromium.org303ada72010-10-27 09:33:13 +00009901static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009902 HandleScope scope;
9903 ASSERT(args.length() == 1);
9904
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009905 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9906 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009907 // Find the number of break points
9908 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9909 if (break_locations->IsUndefined()) return Heap::undefined_value();
9910 // Return array as JS array
9911 return *Factory::NewJSArrayWithElements(
9912 Handle<FixedArray>::cast(break_locations));
9913}
9914
9915
9916// Set a break point in a function
9917// args[0]: function
9918// args[1]: number: break source position (within the function source)
9919// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009920static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009921 HandleScope scope;
9922 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009923 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9924 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009925 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9926 RUNTIME_ASSERT(source_position >= 0);
9927 Handle<Object> break_point_object_arg = args.at<Object>(2);
9928
9929 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009930 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009931
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009932 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009933}
9934
9935
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009936Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9937 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009938 // Iterate the heap looking for SharedFunctionInfo generated from the
9939 // script. The inner most SharedFunctionInfo containing the source position
9940 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009941 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009942 // which is found is not compiled it is compiled and the heap is iterated
9943 // again as the compilation might create inner functions from the newly
9944 // compiled function and the actual requested break point might be in one of
9945 // these functions.
9946 bool done = false;
9947 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009948 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009949 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009950 while (!done) {
9951 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009952 for (HeapObject* obj = iterator.next();
9953 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009954 if (obj->IsSharedFunctionInfo()) {
9955 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9956 if (shared->script() == *script) {
9957 // If the SharedFunctionInfo found has the requested script data and
9958 // contains the source position it is a candidate.
9959 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009960 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009961 start_position = shared->start_position();
9962 }
9963 if (start_position <= position &&
9964 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009965 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009966 // candidate this is the new candidate.
9967 if (target.is_null()) {
9968 target_start_position = start_position;
9969 target = shared;
9970 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009971 if (target_start_position == start_position &&
9972 shared->end_position() == target->end_position()) {
9973 // If a top-level function contain only one function
9974 // declartion the source for the top-level and the function is
9975 // the same. In that case prefer the non top-level function.
9976 if (!shared->is_toplevel()) {
9977 target_start_position = start_position;
9978 target = shared;
9979 }
9980 } else if (target_start_position <= start_position &&
9981 shared->end_position() <= target->end_position()) {
9982 // This containment check includes equality as a function inside
9983 // a top-level function can share either start or end position
9984 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009985 target_start_position = start_position;
9986 target = shared;
9987 }
9988 }
9989 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009990 }
9991 }
9992 }
9993
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009994 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009995 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009996 }
9997
9998 // If the candidate found is compiled we are done. NOTE: when lazy
9999 // compilation of inner functions is introduced some additional checking
10000 // needs to be done here to compile inner functions.
10001 done = target->is_compiled();
10002 if (!done) {
10003 // If the candidate is not compiled compile it to reveal any inner
10004 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010005 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010006 }
10007 }
10008
10009 return *target;
10010}
10011
10012
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010013// Changes the state of a break point in a script and returns source position
10014// where break point was set. NOTE: Regarding performance see the NOTE for
10015// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010016// args[0]: script to set break point in
10017// args[1]: number: break source position (within the script source)
10018// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +000010019static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010020 HandleScope scope;
10021 ASSERT(args.length() == 3);
10022 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10023 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10024 RUNTIME_ASSERT(source_position >= 0);
10025 Handle<Object> break_point_object_arg = args.at<Object>(2);
10026
10027 // Get the script from the script wrapper.
10028 RUNTIME_ASSERT(wrapper->value()->IsScript());
10029 Handle<Script> script(Script::cast(wrapper->value()));
10030
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010031 Object* result = Runtime::FindSharedFunctionInfoInScript(
10032 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010033 if (!result->IsUndefined()) {
10034 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10035 // Find position within function. The script position might be before the
10036 // source position of the first function.
10037 int position;
10038 if (shared->start_position() > source_position) {
10039 position = 0;
10040 } else {
10041 position = source_position - shared->start_position();
10042 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010043 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
10044 position += shared->start_position();
10045 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010046 }
10047 return Heap::undefined_value();
10048}
10049
10050
10051// Clear a break point
10052// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +000010053static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010054 HandleScope scope;
10055 ASSERT(args.length() == 1);
10056 Handle<Object> break_point_object_arg = args.at<Object>(0);
10057
10058 // Clear break point.
10059 Debug::ClearBreakPoint(break_point_object_arg);
10060
10061 return Heap::undefined_value();
10062}
10063
10064
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010065// Change the state of break on exceptions.
10066// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10067// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010068static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010069 HandleScope scope;
10070 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010071 RUNTIME_ASSERT(args[0]->IsNumber());
10072 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010073
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010074 // If the number doesn't match an enum value, the ChangeBreakOnException
10075 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010076 ExceptionBreakType type =
10077 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010078 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010079 Debug::ChangeBreakOnException(type, enable);
10080 return Heap::undefined_value();
10081}
10082
10083
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010084// Returns the state of break on exceptions
10085// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +000010086static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010087 HandleScope scope;
10088 ASSERT(args.length() == 1);
10089 RUNTIME_ASSERT(args[0]->IsNumber());
10090
10091 ExceptionBreakType type =
10092 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
10093 bool result = Debug::IsBreakOnException(type);
10094 return Smi::FromInt(result);
10095}
10096
10097
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010098// Prepare for stepping
10099// args[0]: break id for checking execution state
10100// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010101// args[2]: number of times to perform the step, for step out it is the number
10102// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010103static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010104 HandleScope scope;
10105 ASSERT(args.length() == 3);
10106 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010107 Object* check;
10108 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
10109 if (!maybe_check->ToObject(&check)) return maybe_check;
10110 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010111 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
10112 return Top::Throw(Heap::illegal_argument_symbol());
10113 }
10114
10115 // Get the step action and check validity.
10116 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10117 if (step_action != StepIn &&
10118 step_action != StepNext &&
10119 step_action != StepOut &&
10120 step_action != StepInMin &&
10121 step_action != StepMin) {
10122 return Top::Throw(Heap::illegal_argument_symbol());
10123 }
10124
10125 // Get the number of steps.
10126 int step_count = NumberToInt32(args[2]);
10127 if (step_count < 1) {
10128 return Top::Throw(Heap::illegal_argument_symbol());
10129 }
10130
ager@chromium.orga1645e22009-09-09 19:27:10 +000010131 // Clear all current stepping setup.
10132 Debug::ClearStepping();
10133
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010134 // Prepare step.
10135 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
10136 return Heap::undefined_value();
10137}
10138
10139
10140// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010141static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010142 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010143 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010144 Debug::ClearStepping();
10145 return Heap::undefined_value();
10146}
10147
10148
10149// Creates a copy of the with context chain. The copy of the context chain is
10150// is linked to the function context supplied.
10151static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10152 Handle<Context> function_context) {
10153 // At the bottom of the chain. Return the function context to link to.
10154 if (context_chain->is_function_context()) {
10155 return function_context;
10156 }
10157
10158 // Recursively copy the with contexts.
10159 Handle<Context> previous(context_chain->previous());
10160 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010161 Handle<Context> context = CopyWithContextChain(function_context, previous);
10162 return Factory::NewWithContext(context,
10163 extension,
10164 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010165}
10166
10167
10168// Helper function to find or create the arguments object for
10169// Runtime_DebugEvaluate.
10170static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
10171 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010172 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010173 const ScopeInfo<>* sinfo,
10174 Handle<Context> function_context) {
10175 // Try to find the value of 'arguments' to pass as parameter. If it is not
10176 // found (that is the debugged function does not reference 'arguments' and
10177 // does not support eval) then create an 'arguments' object.
10178 int index;
10179 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010180 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010181 if (index != -1) {
10182 return Handle<Object>(frame->GetExpression(index));
10183 }
10184 }
10185
10186 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010187 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010188 if (index != -1) {
10189 return Handle<Object>(function_context->get(index));
10190 }
10191 }
10192
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010193 const int length = frame->ComputeParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010194 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
10195 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010196
10197 AssertNoAllocation no_gc;
10198 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010199 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010200 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010201 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010202 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010203 return arguments;
10204}
10205
10206
10207// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010208// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010209// extension part has all the parameters and locals of the function on the
10210// stack frame. A function which calls eval with the code to evaluate is then
10211// compiled in this context and called in this context. As this context
10212// replaces the context of the function on the stack frame a new (empty)
10213// function is created as well to be used as the closure for the context.
10214// This function and the context acts as replacements for the function on the
10215// stack frame presenting the same view of the values of parameters and
10216// local variables as if the piece of JavaScript was evaluated at the point
10217// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010218static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010219 HandleScope scope;
10220
10221 // Check the execution state and decode arguments frame and source to be
10222 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010223 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010224 Object* check_result;
10225 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10226 if (!maybe_check_result->ToObject(&check_result)) {
10227 return maybe_check_result;
10228 }
10229 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010230 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10231 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010232 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010233 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010234
10235 // Handle the processing of break.
10236 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010237
10238 // Get the frame where the debugging is performed.
10239 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10240 JavaScriptFrameIterator it(id);
10241 JavaScriptFrame* frame = it.frame();
10242 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010243 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010244 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245
10246 // Traverse the saved contexts chain to find the active context for the
10247 // selected frame.
10248 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010249 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010250 save = save->prev();
10251 }
10252 ASSERT(save != NULL);
10253 SaveContext savex;
10254 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010255
10256 // Create the (empty) function replacing the function on the stack frame for
10257 // the purpose of evaluating in the context created below. It is important
10258 // that this function does not describe any parameters and local variables
10259 // in the context. If it does then this will cause problems with the lookup
10260 // in Context::Lookup, where context slots for parameters and local variables
10261 // are looked at before the extension object.
10262 Handle<JSFunction> go_between =
10263 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
10264 go_between->set_context(function->context());
10265#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010266 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010267 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10268 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10269#endif
10270
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010271 // Materialize the content of the local scope into a JSObject.
10272 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010273 RETURN_IF_EMPTY_HANDLE(local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274
10275 // Allocate a new context for the debug evaluation and set the extension
10276 // object build.
10277 Handle<Context> context =
10278 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010279 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010280 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010281 Handle<Context> frame_context(Context::cast(frame->context()));
10282 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010283 context = CopyWithContextChain(frame_context, context);
10284
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010285 if (additional_context->IsJSObject()) {
10286 context = Factory::NewWithContext(context,
10287 Handle<JSObject>::cast(additional_context), false);
10288 }
10289
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010290 // Wrap the evaluation statement in a new function compiled in the newly
10291 // created context. The function has one parameter which has to be called
10292 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010293 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294 // function(arguments,__source__) {return eval(__source__);}
10295 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010296 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010297 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298 Handle<String> function_source =
10299 Factory::NewStringFromAscii(Vector<const char>(source_str,
10300 source_str_length));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010301
10302 // Currently, the eval code will be executed in non-strict mode,
10303 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010304 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010305 Compiler::CompileEval(function_source,
10306 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010307 context->IsGlobalContext(),
10308 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010309 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010310 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010311 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010312
10313 // Invoke the result of the compilation to get the evaluation function.
10314 bool has_pending_exception;
10315 Handle<Object> receiver(frame->receiver());
10316 Handle<Object> evaluation_function =
10317 Execution::Call(compiled_function, receiver, 0, NULL,
10318 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010319 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010320
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010321 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
10322 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010323
10324 // Invoke the evaluation function and return the result.
10325 const int argc = 2;
10326 Object** argv[argc] = { arguments.location(),
10327 Handle<Object>::cast(source).location() };
10328 Handle<Object> result =
10329 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10330 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010331 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010332
10333 // Skip the global proxy as it has no properties and always delegates to the
10334 // real global object.
10335 if (result->IsJSGlobalProxy()) {
10336 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10337 }
10338
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010339 return *result;
10340}
10341
10342
lrn@chromium.org303ada72010-10-27 09:33:13 +000010343static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010344 HandleScope scope;
10345
10346 // Check the execution state and decode arguments frame and source to be
10347 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010348 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010349 Object* check_result;
10350 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10351 if (!maybe_check_result->ToObject(&check_result)) {
10352 return maybe_check_result;
10353 }
10354 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010355 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010356 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010357 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010358
10359 // Handle the processing of break.
10360 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010361
10362 // Enter the top context from before the debugger was invoked.
10363 SaveContext save;
10364 SaveContext* top = &save;
10365 while (top != NULL && *top->context() == *Debug::debug_context()) {
10366 top = top->prev();
10367 }
10368 if (top != NULL) {
10369 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010370 }
10371
10372 // Get the global context now set to the top context from before the
10373 // debugger was invoked.
10374 Handle<Context> context = Top::global_context();
10375
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010376 bool is_global = true;
10377
10378 if (additional_context->IsJSObject()) {
10379 // Create a function context first, than put 'with' context on top of it.
10380 Handle<JSFunction> go_between = Factory::NewFunction(
10381 Factory::empty_string(), Factory::undefined_value());
10382 go_between->set_context(*context);
10383 context =
10384 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
10385 context->set_extension(JSObject::cast(*additional_context));
10386 is_global = false;
10387 }
10388
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010389 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010390 // Currently, the eval code will be executed in non-strict mode,
10391 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010392 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010393 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010394 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010395 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010396 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
10397 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010398
10399 // Invoke the result of the compilation to get the evaluation function.
10400 bool has_pending_exception;
10401 Handle<Object> receiver = Top::global();
10402 Handle<Object> result =
10403 Execution::Call(compiled_function, receiver, 0, NULL,
10404 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010405 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010406 return *result;
10407}
10408
10409
lrn@chromium.org303ada72010-10-27 09:33:13 +000010410static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010411 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010412 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010413
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010414 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010415 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010416
10417 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010418 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010419 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10420 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10421 // because using
10422 // instances->set(i, *GetScriptWrapper(script))
10423 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10424 // already have deferenced the instances handle.
10425 Handle<JSValue> wrapper = GetScriptWrapper(script);
10426 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010427 }
10428
10429 // Return result as a JS array.
10430 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
10431 Handle<JSArray>::cast(result)->SetContent(*instances);
10432 return *result;
10433}
10434
10435
10436// Helper function used by Runtime_DebugReferencedBy below.
10437static int DebugReferencedBy(JSObject* target,
10438 Object* instance_filter, int max_references,
10439 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010440 JSFunction* arguments_function) {
10441 NoHandleAllocation ha;
10442 AssertNoAllocation no_alloc;
10443
10444 // Iterate the heap.
10445 int count = 0;
10446 JSObject* last = NULL;
10447 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010448 HeapObject* heap_obj = NULL;
10449 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010450 (max_references == 0 || count < max_references)) {
10451 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010452 if (heap_obj->IsJSObject()) {
10453 // Skip context extension objects and argument arrays as these are
10454 // checked in the context of functions using them.
10455 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010456 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010457 obj->map()->constructor() == arguments_function) {
10458 continue;
10459 }
10460
10461 // Check if the JS object has a reference to the object looked for.
10462 if (obj->ReferencesObject(target)) {
10463 // Check instance filter if supplied. This is normally used to avoid
10464 // references from mirror objects (see Runtime_IsInPrototypeChain).
10465 if (!instance_filter->IsUndefined()) {
10466 Object* V = obj;
10467 while (true) {
10468 Object* prototype = V->GetPrototype();
10469 if (prototype->IsNull()) {
10470 break;
10471 }
10472 if (instance_filter == prototype) {
10473 obj = NULL; // Don't add this object.
10474 break;
10475 }
10476 V = prototype;
10477 }
10478 }
10479
10480 if (obj != NULL) {
10481 // Valid reference found add to instance array if supplied an update
10482 // count.
10483 if (instances != NULL && count < instances_size) {
10484 instances->set(count, obj);
10485 }
10486 last = obj;
10487 count++;
10488 }
10489 }
10490 }
10491 }
10492
10493 // Check for circular reference only. This can happen when the object is only
10494 // referenced from mirrors and has a circular reference in which case the
10495 // object is not really alive and would have been garbage collected if not
10496 // referenced from the mirror.
10497 if (count == 1 && last == target) {
10498 count = 0;
10499 }
10500
10501 // Return the number of referencing objects found.
10502 return count;
10503}
10504
10505
10506// Scan the heap for objects with direct references to an object
10507// args[0]: the object to find references to
10508// args[1]: constructor function for instances to exclude (Mirror)
10509// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010510static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010511 ASSERT(args.length() == 3);
10512
10513 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010514 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010515
10516 // Check parameters.
10517 CONVERT_CHECKED(JSObject, target, args[0]);
10518 Object* instance_filter = args[1];
10519 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10520 instance_filter->IsJSObject());
10521 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10522 RUNTIME_ASSERT(max_references >= 0);
10523
10524 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010525 JSObject* arguments_boilerplate =
10526 Top::context()->global_context()->arguments_boilerplate();
10527 JSFunction* arguments_function =
10528 JSFunction::cast(arguments_boilerplate->map()->constructor());
10529
10530 // Get the number of referencing objects.
10531 int count;
10532 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010533 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534
10535 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010536 Object* object;
10537 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10538 if (!maybe_object->ToObject(&object)) return maybe_object;
10539 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010540 FixedArray* instances = FixedArray::cast(object);
10541
10542 // Fill the referencing objects.
10543 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010544 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010545
10546 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010547 Object* result;
10548 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10549 Top::context()->global_context()->array_function());
10550 if (!maybe_result->ToObject(&result)) return maybe_result;
10551 }
10552 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010553 return result;
10554}
10555
10556
10557// Helper function used by Runtime_DebugConstructedBy below.
10558static int DebugConstructedBy(JSFunction* constructor, int max_references,
10559 FixedArray* instances, int instances_size) {
10560 AssertNoAllocation no_alloc;
10561
10562 // Iterate the heap.
10563 int count = 0;
10564 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010565 HeapObject* heap_obj = NULL;
10566 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010567 (max_references == 0 || count < max_references)) {
10568 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010569 if (heap_obj->IsJSObject()) {
10570 JSObject* obj = JSObject::cast(heap_obj);
10571 if (obj->map()->constructor() == constructor) {
10572 // Valid reference found add to instance array if supplied an update
10573 // count.
10574 if (instances != NULL && count < instances_size) {
10575 instances->set(count, obj);
10576 }
10577 count++;
10578 }
10579 }
10580 }
10581
10582 // Return the number of referencing objects found.
10583 return count;
10584}
10585
10586
10587// Scan the heap for objects constructed by a specific function.
10588// args[0]: the constructor to find instances of
10589// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010590static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010591 ASSERT(args.length() == 2);
10592
10593 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010594 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010595
10596 // Check parameters.
10597 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10598 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10599 RUNTIME_ASSERT(max_references >= 0);
10600
10601 // Get the number of referencing objects.
10602 int count;
10603 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10604
10605 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010606 Object* object;
10607 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10608 if (!maybe_object->ToObject(&object)) return maybe_object;
10609 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010610 FixedArray* instances = FixedArray::cast(object);
10611
10612 // Fill the referencing objects.
10613 count = DebugConstructedBy(constructor, max_references, instances, count);
10614
10615 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010616 Object* result;
10617 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10618 Top::context()->global_context()->array_function());
10619 if (!maybe_result->ToObject(&result)) return maybe_result;
10620 }
10621 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010622 return result;
10623}
10624
10625
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010626// Find the effective prototype object as returned by __proto__.
10627// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010628static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010629 ASSERT(args.length() == 1);
10630
10631 CONVERT_CHECKED(JSObject, obj, args[0]);
10632
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010633 // Use the __proto__ accessor.
10634 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010635}
10636
10637
lrn@chromium.org303ada72010-10-27 09:33:13 +000010638static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010639 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010640 CPU::DebugBreak();
10641 return Heap::undefined_value();
10642}
10643
10644
lrn@chromium.org303ada72010-10-27 09:33:13 +000010645static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010646#ifdef DEBUG
10647 HandleScope scope;
10648 ASSERT(args.length() == 1);
10649 // Get the function and make sure it is compiled.
10650 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010651 Handle<SharedFunctionInfo> shared(func->shared());
10652 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010653 return Failure::Exception();
10654 }
10655 func->code()->PrintLn();
10656#endif // DEBUG
10657 return Heap::undefined_value();
10658}
ager@chromium.org9085a012009-05-11 19:22:57 +000010659
10660
lrn@chromium.org303ada72010-10-27 09:33:13 +000010661static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010662#ifdef DEBUG
10663 HandleScope scope;
10664 ASSERT(args.length() == 1);
10665 // Get the function and make sure it is compiled.
10666 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010667 Handle<SharedFunctionInfo> shared(func->shared());
10668 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010669 return Failure::Exception();
10670 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010671 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010672#endif // DEBUG
10673 return Heap::undefined_value();
10674}
10675
10676
lrn@chromium.org303ada72010-10-27 09:33:13 +000010677static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010678 NoHandleAllocation ha;
10679 ASSERT(args.length() == 1);
10680
10681 CONVERT_CHECKED(JSFunction, f, args[0]);
10682 return f->shared()->inferred_name();
10683}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010684
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010685
10686static int FindSharedFunctionInfosForScript(Script* script,
10687 FixedArray* buffer) {
10688 AssertNoAllocation no_allocations;
10689
10690 int counter = 0;
10691 int buffer_size = buffer->length();
10692 HeapIterator iterator;
10693 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10694 ASSERT(obj != NULL);
10695 if (!obj->IsSharedFunctionInfo()) {
10696 continue;
10697 }
10698 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10699 if (shared->script() != script) {
10700 continue;
10701 }
10702 if (counter < buffer_size) {
10703 buffer->set(counter, shared);
10704 }
10705 counter++;
10706 }
10707 return counter;
10708}
10709
10710// For a script finds all SharedFunctionInfo's in the heap that points
10711// to this script. Returns JSArray of SharedFunctionInfo wrapped
10712// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010713static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010714 Arguments args) {
10715 ASSERT(args.length() == 1);
10716 HandleScope scope;
10717 CONVERT_CHECKED(JSValue, script_value, args[0]);
10718
10719 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10720
10721 const int kBufferSize = 32;
10722
10723 Handle<FixedArray> array;
10724 array = Factory::NewFixedArray(kBufferSize);
10725 int number = FindSharedFunctionInfosForScript(*script, *array);
10726 if (number > kBufferSize) {
10727 array = Factory::NewFixedArray(number);
10728 FindSharedFunctionInfosForScript(*script, *array);
10729 }
10730
10731 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10732 result->set_length(Smi::FromInt(number));
10733
10734 LiveEdit::WrapSharedFunctionInfos(result);
10735
10736 return *result;
10737}
10738
10739// For a script calculates compilation information about all its functions.
10740// The script source is explicitly specified by the second argument.
10741// The source of the actual script is not used, however it is important that
10742// all generated code keeps references to this particular instance of script.
10743// Returns a JSArray of compilation infos. The array is ordered so that
10744// each function with all its descendant is always stored in a continues range
10745// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010746static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010747 ASSERT(args.length() == 2);
10748 HandleScope scope;
10749 CONVERT_CHECKED(JSValue, script, args[0]);
10750 CONVERT_ARG_CHECKED(String, source, 1);
10751 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10752
10753 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10754
10755 if (Top::has_pending_exception()) {
10756 return Failure::Exception();
10757 }
10758
10759 return result;
10760}
10761
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010762// Changes the source of the script to a new_source.
10763// If old_script_name is provided (i.e. is a String), also creates a copy of
10764// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010765static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010766 ASSERT(args.length() == 3);
10767 HandleScope scope;
10768 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10769 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010770 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010771
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010772 CONVERT_CHECKED(Script, original_script_pointer,
10773 original_script_value->value());
10774 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010775
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010776 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10777 new_source,
10778 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010779
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010780 if (old_script->IsScript()) {
10781 Handle<Script> script_handle(Script::cast(old_script));
10782 return *(GetScriptWrapper(script_handle));
10783 } else {
10784 return Heap::null_value();
10785 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010786}
10787
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010788
10789static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10790 ASSERT(args.length() == 1);
10791 HandleScope scope;
10792 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10793 return LiveEdit::FunctionSourceUpdated(shared_info);
10794}
10795
10796
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010797// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010798static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010799 ASSERT(args.length() == 2);
10800 HandleScope scope;
10801 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10802 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10803
ager@chromium.orgac091b72010-05-05 07:34:42 +000010804 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010805}
10806
10807// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010808static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010809 ASSERT(args.length() == 2);
10810 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010811 Handle<Object> function_object(args[0]);
10812 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010813
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010814 if (function_object->IsJSValue()) {
10815 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10816 if (script_object->IsJSValue()) {
10817 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10818 script_object = Handle<Object>(script);
10819 }
10820
10821 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10822 } else {
10823 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10824 // and we check it in this function.
10825 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010826
10827 return Heap::undefined_value();
10828}
10829
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010830
10831// In a code of a parent function replaces original function as embedded object
10832// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010833static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010834 ASSERT(args.length() == 3);
10835 HandleScope scope;
10836
10837 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10838 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10839 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10840
10841 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10842 subst_wrapper);
10843
10844 return Heap::undefined_value();
10845}
10846
10847
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010848// Updates positions of a shared function info (first parameter) according
10849// to script source change. Text change is described in second parameter as
10850// array of groups of 3 numbers:
10851// (change_begin, change_end, change_end_new_position).
10852// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010853static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010854 ASSERT(args.length() == 2);
10855 HandleScope scope;
10856 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10857 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10858
ager@chromium.orgac091b72010-05-05 07:34:42 +000010859 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010860}
10861
10862
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010863// For array of SharedFunctionInfo's (each wrapped in JSValue)
10864// checks that none of them have activations on stacks (of any thread).
10865// Returns array of the same length with corresponding results of
10866// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010867static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010868 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010869 HandleScope scope;
10870 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010871 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010872
ager@chromium.org357bf652010-04-12 11:30:10 +000010873 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010874}
10875
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010876// Compares 2 strings line-by-line, then token-wise and returns diff in form
10877// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
10878// of diff chunks.
10879static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010880 ASSERT(args.length() == 2);
10881 HandleScope scope;
10882 CONVERT_ARG_CHECKED(String, s1, 0);
10883 CONVERT_ARG_CHECKED(String, s2, 1);
10884
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010885 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010886}
10887
10888
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010889
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010890// A testing entry. Returns statement position which is the closest to
10891// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010892static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010893 ASSERT(args.length() == 2);
10894 HandleScope scope;
10895 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10896 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10897
10898 Handle<Code> code(function->code());
10899
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010900 if (code->kind() != Code::FUNCTION &&
10901 code->kind() != Code::OPTIMIZED_FUNCTION) {
10902 return Heap::undefined_value();
10903 }
10904
10905 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010906 int closest_pc = 0;
10907 int distance = kMaxInt;
10908 while (!it.done()) {
10909 int statement_position = static_cast<int>(it.rinfo()->data());
10910 // Check if this break point is closer that what was previously found.
10911 if (source_position <= statement_position &&
10912 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010913 closest_pc =
10914 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010915 distance = statement_position - source_position;
10916 // Check whether we can't get any closer.
10917 if (distance == 0) break;
10918 }
10919 it.next();
10920 }
10921
10922 return Smi::FromInt(closest_pc);
10923}
10924
10925
ager@chromium.org357bf652010-04-12 11:30:10 +000010926// Calls specified function with or without entering the debugger.
10927// This is used in unit tests to run code as if debugger is entered or simply
10928// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010929static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010930 ASSERT(args.length() == 2);
10931 HandleScope scope;
10932 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10933 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10934
10935 Handle<Object> result;
10936 bool pending_exception;
10937 {
10938 if (without_debugger) {
10939 result = Execution::Call(function, Top::global(), 0, NULL,
10940 &pending_exception);
10941 } else {
10942 EnterDebugger enter_debugger;
10943 result = Execution::Call(function, Top::global(), 0, NULL,
10944 &pending_exception);
10945 }
10946 }
10947 if (!pending_exception) {
10948 return *result;
10949 } else {
10950 return Failure::Exception();
10951 }
10952}
10953
10954
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010955// Sets a v8 flag.
10956static MaybeObject* Runtime_SetFlags(Arguments args) {
10957 CONVERT_CHECKED(String, arg, args[0]);
10958 SmartPointer<char> flags =
10959 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10960 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10961 return Heap::undefined_value();
10962}
10963
10964
10965// Performs a GC.
10966// Presently, it only does a full GC.
10967static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10968 Heap::CollectAllGarbage(true);
10969 return Heap::undefined_value();
10970}
10971
10972
10973// Gets the current heap usage.
10974static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10975 int usage = static_cast<int>(Heap::SizeOfObjects());
10976 if (!Smi::IsValid(usage)) {
10977 return *Factory::NewNumberFromInt(usage);
10978 }
10979 return Smi::FromInt(usage);
10980}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010981
10982
10983// Captures a live object list from the present heap.
10984static MaybeObject* Runtime_HasLOLEnabled(Arguments args) {
10985#ifdef LIVE_OBJECT_LIST
10986 return Heap::true_value();
10987#else
10988 return Heap::false_value();
10989#endif
10990}
10991
10992
10993// Captures a live object list from the present heap.
10994static MaybeObject* Runtime_CaptureLOL(Arguments args) {
10995#ifdef LIVE_OBJECT_LIST
10996 return LiveObjectList::Capture();
10997#else
10998 return Heap::undefined_value();
10999#endif
11000}
11001
11002
11003// Deletes the specified live object list.
11004static MaybeObject* Runtime_DeleteLOL(Arguments args) {
11005#ifdef LIVE_OBJECT_LIST
11006 CONVERT_SMI_CHECKED(id, args[0]);
11007 bool success = LiveObjectList::Delete(id);
11008 return success ? Heap::true_value() : Heap::false_value();
11009#else
11010 return Heap::undefined_value();
11011#endif
11012}
11013
11014
11015// Generates the response to a debugger request for a dump of the objects
11016// contained in the difference between the captured live object lists
11017// specified by id1 and id2.
11018// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11019// dumped.
11020static MaybeObject* Runtime_DumpLOL(Arguments args) {
11021#ifdef LIVE_OBJECT_LIST
11022 HandleScope scope;
11023 CONVERT_SMI_CHECKED(id1, args[0]);
11024 CONVERT_SMI_CHECKED(id2, args[1]);
11025 CONVERT_SMI_CHECKED(start, args[2]);
11026 CONVERT_SMI_CHECKED(count, args[3]);
11027 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11028 EnterDebugger enter_debugger;
11029 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11030#else
11031 return Heap::undefined_value();
11032#endif
11033}
11034
11035
11036// Gets the specified object as requested by the debugger.
11037// This is only used for obj ids shown in live object lists.
11038static MaybeObject* Runtime_GetLOLObj(Arguments args) {
11039#ifdef LIVE_OBJECT_LIST
11040 CONVERT_SMI_CHECKED(obj_id, args[0]);
11041 Object* result = LiveObjectList::GetObj(obj_id);
11042 return result;
11043#else
11044 return Heap::undefined_value();
11045#endif
11046}
11047
11048
11049// Gets the obj id for the specified address if valid.
11050// This is only used for obj ids shown in live object lists.
11051static MaybeObject* Runtime_GetLOLObjId(Arguments args) {
11052#ifdef LIVE_OBJECT_LIST
11053 HandleScope scope;
11054 CONVERT_ARG_CHECKED(String, address, 0);
11055 Object* result = LiveObjectList::GetObjId(address);
11056 return result;
11057#else
11058 return Heap::undefined_value();
11059#endif
11060}
11061
11062
11063// Gets the retainers that references the specified object alive.
11064static MaybeObject* Runtime_GetLOLObjRetainers(Arguments args) {
11065#ifdef LIVE_OBJECT_LIST
11066 HandleScope scope;
11067 CONVERT_SMI_CHECKED(obj_id, args[0]);
11068 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11069 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11070 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11071 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11072 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11073
11074 Handle<JSObject> instance_filter;
11075 if (args[1]->IsJSObject()) {
11076 instance_filter = args.at<JSObject>(1);
11077 }
11078 bool verbose = false;
11079 if (args[2]->IsBoolean()) {
11080 verbose = args[2]->IsTrue();
11081 }
11082 int start = 0;
11083 if (args[3]->IsSmi()) {
11084 start = Smi::cast(args[3])->value();
11085 }
11086 int limit = Smi::kMaxValue;
11087 if (args[4]->IsSmi()) {
11088 limit = Smi::cast(args[4])->value();
11089 }
11090
11091 return LiveObjectList::GetObjRetainers(obj_id,
11092 instance_filter,
11093 verbose,
11094 start,
11095 limit,
11096 filter_obj);
11097#else
11098 return Heap::undefined_value();
11099#endif
11100}
11101
11102
11103// Gets the reference path between 2 objects.
11104static MaybeObject* Runtime_GetLOLPath(Arguments args) {
11105#ifdef LIVE_OBJECT_LIST
11106 HandleScope scope;
11107 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11108 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11109 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11110
11111 Handle<JSObject> instance_filter;
11112 if (args[2]->IsJSObject()) {
11113 instance_filter = args.at<JSObject>(2);
11114 }
11115
11116 Object* result =
11117 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11118 return result;
11119#else
11120 return Heap::undefined_value();
11121#endif
11122}
11123
11124
11125// Generates the response to a debugger request for a list of all
11126// previously captured live object lists.
11127static MaybeObject* Runtime_InfoLOL(Arguments args) {
11128#ifdef LIVE_OBJECT_LIST
11129 CONVERT_SMI_CHECKED(start, args[0]);
11130 CONVERT_SMI_CHECKED(count, args[1]);
11131 return LiveObjectList::Info(start, count);
11132#else
11133 return Heap::undefined_value();
11134#endif
11135}
11136
11137
11138// Gets a dump of the specified object as requested by the debugger.
11139// This is only used for obj ids shown in live object lists.
11140static MaybeObject* Runtime_PrintLOLObj(Arguments args) {
11141#ifdef LIVE_OBJECT_LIST
11142 HandleScope scope;
11143 CONVERT_SMI_CHECKED(obj_id, args[0]);
11144 Object* result = LiveObjectList::PrintObj(obj_id);
11145 return result;
11146#else
11147 return Heap::undefined_value();
11148#endif
11149}
11150
11151
11152// Resets and releases all previously captured live object lists.
11153static MaybeObject* Runtime_ResetLOL(Arguments args) {
11154#ifdef LIVE_OBJECT_LIST
11155 LiveObjectList::Reset();
11156 return Heap::undefined_value();
11157#else
11158 return Heap::undefined_value();
11159#endif
11160}
11161
11162
11163// Generates the response to a debugger request for a summary of the types
11164// of objects in the difference between the captured live object lists
11165// specified by id1 and id2.
11166// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11167// summarized.
11168static MaybeObject* Runtime_SummarizeLOL(Arguments args) {
11169#ifdef LIVE_OBJECT_LIST
11170 HandleScope scope;
11171 CONVERT_SMI_CHECKED(id1, args[0]);
11172 CONVERT_SMI_CHECKED(id2, args[1]);
11173 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11174
11175 EnterDebugger enter_debugger;
11176 return LiveObjectList::Summarize(id1, id2, filter_obj);
11177#else
11178 return Heap::undefined_value();
11179#endif
11180}
11181
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011182#endif // ENABLE_DEBUGGER_SUPPORT
11183
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011184
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011185#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000011186static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011187 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011188 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011189
11190 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011191 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11192 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011193 return Heap::undefined_value();
11194}
11195
11196
lrn@chromium.org303ada72010-10-27 09:33:13 +000011197static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011198 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011199 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011200
11201 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011202 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11203 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011204 return Heap::undefined_value();
11205}
11206
11207#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011208
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011209// Finds the script object from the script data. NOTE: This operation uses
11210// heap traversal to find the function generated for the source position
11211// for the requested break point. For lazily compiled functions several heap
11212// traversals might be required rendering this operation as a rather slow
11213// operation. However for setting break points which is normally done through
11214// some kind of user interaction the performance is not crucial.
11215static Handle<Object> Runtime_GetScriptFromScriptName(
11216 Handle<String> script_name) {
11217 // Scan the heap for Script objects to find the script with the requested
11218 // script data.
11219 Handle<Script> script;
11220 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011221 HeapObject* obj = NULL;
11222 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011223 // If a script is found check if it has the script data requested.
11224 if (obj->IsScript()) {
11225 if (Script::cast(obj)->name()->IsString()) {
11226 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11227 script = Handle<Script>(Script::cast(obj));
11228 }
11229 }
11230 }
11231 }
11232
11233 // If no script with the requested script data is found return undefined.
11234 if (script.is_null()) return Factory::undefined_value();
11235
11236 // Return the script found.
11237 return GetScriptWrapper(script);
11238}
11239
11240
11241// Get the script object from script data. NOTE: Regarding performance
11242// see the NOTE for GetScriptFromScriptData.
11243// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000011244static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011245 HandleScope scope;
11246
11247 ASSERT(args.length() == 1);
11248
11249 CONVERT_CHECKED(String, script_name, args[0]);
11250
11251 // Find the requested script.
11252 Handle<Object> result =
11253 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11254 return *result;
11255}
11256
11257
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011258// Determines whether the given stack frame should be displayed in
11259// a stack trace. The caller is the error constructor that asked
11260// for the stack trace to be collected. The first time a construct
11261// call to this function is encountered it is skipped. The seen_caller
11262// in/out parameter is used to remember if the caller has been seen
11263// yet.
11264static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11265 bool* seen_caller) {
11266 // Only display JS frames.
11267 if (!raw_frame->is_java_script())
11268 return false;
11269 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11270 Object* raw_fun = frame->function();
11271 // Not sure when this can happen but skip it just in case.
11272 if (!raw_fun->IsJSFunction())
11273 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011274 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011275 *seen_caller = true;
11276 return false;
11277 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011278 // Skip all frames until we've seen the caller. Also, skip the most
11279 // obvious builtin calls. Some builtin calls (such as Number.ADD
11280 // which is invoked using 'call') are very difficult to recognize
11281 // so we're leaving them in for now.
11282 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011283}
11284
11285
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011286// Collect the raw data for a stack trace. Returns an array of 4
11287// element segments each containing a receiver, function, code and
11288// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011289static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011290 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011291 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011292 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11293
11294 HandleScope scope;
11295
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011296 limit = Max(limit, 0); // Ensure that limit is not negative.
11297 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011298 Handle<FixedArray> elements =
11299 Factory::NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011300
11301 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011302 // If the caller parameter is a function we skip frames until we're
11303 // under it before starting to collect.
11304 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011305 int cursor = 0;
11306 int frames_seen = 0;
11307 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011308 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011309 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011310 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011311 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011312 List<FrameSummary> frames(3); // Max 2 levels of inlining.
11313 frame->Summarize(&frames);
11314 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011315 if (cursor + 4 > elements->length()) {
11316 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11317 Handle<FixedArray> new_elements =
11318 Factory::NewFixedArrayWithHoles(new_capacity);
11319 for (int i = 0; i < cursor; i++) {
11320 new_elements->set(i, elements->get(i));
11321 }
11322 elements = new_elements;
11323 }
11324 ASSERT(cursor + 4 <= elements->length());
11325
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011326 Handle<Object> recv = frames[i].receiver();
11327 Handle<JSFunction> fun = frames[i].function();
11328 Handle<Code> code = frames[i].code();
11329 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011330 elements->set(cursor++, *recv);
11331 elements->set(cursor++, *fun);
11332 elements->set(cursor++, *code);
11333 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011334 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011335 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011336 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011337 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011338 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011339 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011340 return *result;
11341}
11342
11343
ager@chromium.org3811b432009-10-28 14:53:37 +000011344// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011345static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011346 ASSERT_EQ(args.length(), 0);
11347
11348 NoHandleAllocation ha;
11349
11350 const char* version_string = v8::V8::GetVersion();
11351
11352 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
11353}
11354
11355
lrn@chromium.org303ada72010-10-27 09:33:13 +000011356static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011357 ASSERT(args.length() == 2);
11358 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11359 Smi::cast(args[1])->value());
11360 Top::PrintStack();
11361 OS::Abort();
11362 UNREACHABLE();
11363 return NULL;
11364}
11365
11366
lrn@chromium.org303ada72010-10-27 09:33:13 +000011367static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011368 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011369 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011370 Object* key = args[1];
11371
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011372 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011373 Object* o = cache->get(finger_index);
11374 if (o == key) {
11375 // The fastest case: hit the same place again.
11376 return cache->get(finger_index + 1);
11377 }
11378
11379 for (int i = finger_index - 2;
11380 i >= JSFunctionResultCache::kEntriesIndex;
11381 i -= 2) {
11382 o = cache->get(i);
11383 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011384 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011385 return cache->get(i + 1);
11386 }
11387 }
11388
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011389 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011390 ASSERT(size <= cache->length());
11391
11392 for (int i = size - 2; i > finger_index; i -= 2) {
11393 o = cache->get(i);
11394 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011395 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011396 return cache->get(i + 1);
11397 }
11398 }
11399
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011400 // There is no value in the cache. Invoke the function and cache result.
11401 HandleScope scope;
11402
11403 Handle<JSFunctionResultCache> cache_handle(cache);
11404 Handle<Object> key_handle(key);
11405 Handle<Object> value;
11406 {
11407 Handle<JSFunction> factory(JSFunction::cast(
11408 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11409 // TODO(antonm): consider passing a receiver when constructing a cache.
11410 Handle<Object> receiver(Top::global_context()->global());
11411 // This handle is nor shared, nor used later, so it's safe.
11412 Object** argv[] = { key_handle.location() };
11413 bool pending_exception = false;
11414 value = Execution::Call(factory,
11415 receiver,
11416 1,
11417 argv,
11418 &pending_exception);
11419 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011420 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011421
11422#ifdef DEBUG
11423 cache_handle->JSFunctionResultCacheVerify();
11424#endif
11425
11426 // Function invocation may have cleared the cache. Reread all the data.
11427 finger_index = cache_handle->finger_index();
11428 size = cache_handle->size();
11429
11430 // If we have spare room, put new data into it, otherwise evict post finger
11431 // entry which is likely to be the least recently used.
11432 int index = -1;
11433 if (size < cache_handle->length()) {
11434 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11435 index = size;
11436 } else {
11437 index = finger_index + JSFunctionResultCache::kEntrySize;
11438 if (index == cache_handle->length()) {
11439 index = JSFunctionResultCache::kEntriesIndex;
11440 }
11441 }
11442
11443 ASSERT(index % 2 == 0);
11444 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11445 ASSERT(index < cache_handle->length());
11446
11447 cache_handle->set(index, *key_handle);
11448 cache_handle->set(index + 1, *value);
11449 cache_handle->set_finger_index(index);
11450
11451#ifdef DEBUG
11452 cache_handle->JSFunctionResultCacheVerify();
11453#endif
11454
11455 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011456}
11457
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011458
11459static MaybeObject* Runtime_NewMessageObject(Arguments args) {
11460 HandleScope scope;
11461 CONVERT_ARG_CHECKED(String, type, 0);
11462 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
11463 return *Factory::NewJSMessageObject(type,
11464 arguments,
11465 0,
11466 0,
11467 Factory::undefined_value(),
11468 Factory::undefined_value(),
11469 Factory::undefined_value());
11470}
11471
11472
11473static MaybeObject* Runtime_MessageGetType(Arguments args) {
11474 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11475 return message->type();
11476}
11477
11478
11479static MaybeObject* Runtime_MessageGetArguments(Arguments args) {
11480 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11481 return message->arguments();
11482}
11483
11484
11485static MaybeObject* Runtime_MessageGetStartPosition(Arguments args) {
11486 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11487 return Smi::FromInt(message->start_position());
11488}
11489
11490
11491static MaybeObject* Runtime_MessageGetScript(Arguments args) {
11492 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11493 return message->script();
11494}
11495
11496
kasper.lund44510672008-07-25 07:37:58 +000011497#ifdef DEBUG
11498// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11499// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011500static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000011501 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011502 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011503#define COUNT_ENTRY(Name, argc, ressize) + 1
11504 int entry_count = 0
11505 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
11506 INLINE_FUNCTION_LIST(COUNT_ENTRY)
11507 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
11508#undef COUNT_ENTRY
11509 Handle<FixedArray> elements = Factory::NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011510 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011511 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011512#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011513 { \
11514 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011515 Handle<String> name; \
11516 /* Inline runtime functions have an underscore in front of the name. */ \
11517 if (inline_runtime_functions) { \
11518 name = Factory::NewStringFromAscii( \
11519 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11520 } else { \
11521 name = Factory::NewStringFromAscii( \
11522 Vector<const char>(#Name, StrLength(#Name))); \
11523 } \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011524 Handle<FixedArray> pair_elements = Factory::NewFixedArray(2); \
11525 pair_elements->set(0, *name); \
11526 pair_elements->set(1, Smi::FromInt(argc)); \
11527 Handle<JSArray> pair = Factory::NewJSArrayWithElements(pair_elements); \
11528 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011529 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011530 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011531 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011532 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011533 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011534 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011535#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011536 ASSERT_EQ(index, entry_count);
11537 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011538 return *result;
11539}
kasper.lund44510672008-07-25 07:37:58 +000011540#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011541
11542
lrn@chromium.org303ada72010-10-27 09:33:13 +000011543static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011544 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011545 CONVERT_CHECKED(String, format, args[0]);
11546 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011547 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011548 Logger::LogRuntime(chars, elms);
11549 return Heap::undefined_value();
11550}
11551
11552
lrn@chromium.org303ada72010-10-27 09:33:13 +000011553static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011554 UNREACHABLE(); // implemented as macro in the parser
11555 return NULL;
11556}
11557
11558
11559// ----------------------------------------------------------------------------
11560// Implementation of Runtime
11561
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011562#define F(name, number_of_args, result_size) \
11563 { Runtime::k##name, Runtime::RUNTIME, #name, \
11564 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011565
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011566
11567#define I(name, number_of_args, result_size) \
11568 { Runtime::kInline##name, Runtime::INLINE, \
11569 "_" #name, NULL, number_of_args, result_size },
11570
11571Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011572 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011573 INLINE_FUNCTION_LIST(I)
11574 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011575};
11576
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011577
lrn@chromium.org303ada72010-10-27 09:33:13 +000011578MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011579 ASSERT(dictionary != NULL);
11580 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11581 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011582 Object* name_symbol;
11583 { MaybeObject* maybe_name_symbol =
11584 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
11585 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11586 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011587 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011588 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11589 String::cast(name_symbol),
11590 Smi::FromInt(i),
11591 PropertyDetails(NONE, NORMAL));
11592 if (!maybe_dictionary->ToObject(&dictionary)) {
11593 // Non-recoverable failure. Calling code must restart heap
11594 // initialization.
11595 return maybe_dictionary;
11596 }
11597 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011598 }
11599 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011600}
11601
11602
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011603Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11604 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
11605 if (entry != kNotFound) {
11606 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
11607 int function_index = Smi::cast(smi_index)->value();
11608 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011609 }
11610 return NULL;
11611}
11612
11613
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011614Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
11615 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11616}
11617
11618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011619void Runtime::PerformGC(Object* result) {
11620 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011621 if (failure->IsRetryAfterGC()) {
11622 // Try to do a garbage collection; ignore it if it fails. The C
11623 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000011624 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011625 } else {
11626 // Handle last resort GC and make sure to allow future allocations
11627 // to grow the heap without causing GCs (if possible).
11628 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000011629 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011630 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011631}
11632
11633
11634} } // namespace v8::internal