blob: 965a083a8d97335f31c02292e31f76cf6533c027 [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.
ager@chromium.org3811b432009-10-28 14:53:37 +0000175 ASSERT(!copy->HasPixelElements() && !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.
4347 const uint32_t n = frame->GetProvidedParametersCount();
4348
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();
6902 int argc = frame->GetProvidedParametersCount();
6903
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());
7741 const int length = frame->GetProvidedParametersCount();
7742 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) {
8330 case JSObject::PIXEL_ELEMENTS: {
8331 dense_elements_length =
8332 PixelArray::cast(object->elements())->length();
8333 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 }
8456 case JSObject::PIXEL_ELEMENTS: {
8457 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
8458 for (uint32_t j = 0; j < length; j++) {
8459 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8460 visitor->visit(j, e);
8461 }
8462 break;
8463 }
8464 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8465 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8466 receiver, true, true, visitor);
8467 break;
8468 }
8469 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8470 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8471 receiver, true, true, visitor);
8472 break;
8473 }
8474 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8475 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8476 receiver, true, true, visitor);
8477 break;
8478 }
8479 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8480 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8481 receiver, true, true, visitor);
8482 break;
8483 }
8484 case JSObject::EXTERNAL_INT_ELEMENTS: {
8485 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8486 receiver, true, false, visitor);
8487 break;
8488 }
8489 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8490 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8491 receiver, true, false, visitor);
8492 break;
8493 }
8494 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8495 IterateExternalArrayElements<ExternalFloatArray, float>(
8496 receiver, false, false, visitor);
8497 break;
8498 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008499 default:
8500 UNREACHABLE();
8501 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008502 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008503 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008504 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008505}
8506
8507
8508/**
8509 * Array::concat implementation.
8510 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008511 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008512 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008513 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008514static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008515 ASSERT(args.length() == 1);
8516 HandleScope handle_scope;
8517
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008518 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8519 int argument_count = static_cast<int>(arguments->length()->Number());
8520 RUNTIME_ASSERT(arguments->HasFastElements());
8521 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008522
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008523 // Pass 1: estimate the length and number of elements of the result.
8524 // The actual length can be larger if any of the arguments have getters
8525 // that mutate other arguments (but will otherwise be precise).
8526 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008527
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008528 uint32_t estimate_result_length = 0;
8529 uint32_t estimate_nof_elements = 0;
8530 {
8531 for (int i = 0; i < argument_count; i++) {
8532 HandleScope loop_scope;
8533 Handle<Object> obj(elements->get(i));
8534 uint32_t length_estimate;
8535 uint32_t element_estimate;
8536 if (obj->IsJSArray()) {
8537 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8538 length_estimate =
8539 static_cast<uint32_t>(array->length()->Number());
8540 element_estimate =
8541 EstimateElementCount(array);
8542 } else {
8543 length_estimate = 1;
8544 element_estimate = 1;
8545 }
8546 // Avoid overflows by capping at kMaxElementCount.
8547 if (JSObject::kMaxElementCount - estimate_result_length <
8548 length_estimate) {
8549 estimate_result_length = JSObject::kMaxElementCount;
8550 } else {
8551 estimate_result_length += length_estimate;
8552 }
8553 if (JSObject::kMaxElementCount - estimate_nof_elements <
8554 element_estimate) {
8555 estimate_nof_elements = JSObject::kMaxElementCount;
8556 } else {
8557 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008558 }
8559 }
8560 }
8561
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008562 // If estimated number of elements is more than half of length, a
8563 // fixed array (fast case) is more time and space-efficient than a
8564 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008565 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008566
8567 Handle<FixedArray> storage;
8568 if (fast_case) {
8569 // The backing storage array must have non-existing elements to
8570 // preserve holes across concat operations.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008571 storage = Factory::NewFixedArrayWithHoles(estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008572 } else {
8573 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8574 uint32_t at_least_space_for = estimate_nof_elements +
8575 (estimate_nof_elements >> 2);
8576 storage = Handle<FixedArray>::cast(
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008577 Factory::NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008578 }
8579
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008580 ArrayConcatVisitor visitor(storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008581
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008582 for (int i = 0; i < argument_count; i++) {
8583 Handle<Object> obj(elements->get(i));
8584 if (obj->IsJSArray()) {
8585 Handle<JSArray> array = Handle<JSArray>::cast(obj);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008586 if (!IterateElements(array, &visitor)) {
8587 return Failure::Exception();
8588 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008589 } else {
8590 visitor.visit(0, obj);
8591 visitor.increase_index_offset(1);
8592 }
8593 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008594
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008595 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008596}
8597
8598
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008599// This will not allocate (flatten the string), but it may run
8600// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008601static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008602 NoHandleAllocation ha;
8603 ASSERT(args.length() == 1);
8604
8605 CONVERT_CHECKED(String, string, args[0]);
8606 StringInputBuffer buffer(string);
8607 while (buffer.has_more()) {
8608 uint16_t character = buffer.GetNext();
8609 PrintF("%c", character);
8610 }
8611 return string;
8612}
8613
ager@chromium.org5ec48922009-05-05 07:25:34 +00008614// Moves all own elements of an object, that are below a limit, to positions
8615// starting at zero. All undefined values are placed after non-undefined values,
8616// and are followed by non-existing element. Does not change the length
8617// property.
8618// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008619static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008620 ASSERT(args.length() == 2);
8621 CONVERT_CHECKED(JSObject, object, args[0]);
8622 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8623 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008624}
8625
8626
8627// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008628static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008629 ASSERT(args.length() == 2);
8630 CONVERT_CHECKED(JSArray, from, args[0]);
8631 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008632 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008633 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008634 if (new_elements->map() == Heap::fixed_array_map() ||
8635 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008636 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008637 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008638 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008639 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008640 Object* new_map;
8641 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008642 to->set_map(Map::cast(new_map));
8643 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008644 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008645 Object* obj;
8646 { MaybeObject* maybe_obj = from->ResetElements();
8647 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8648 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008649 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008650 return to;
8651}
8652
8653
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008654// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008655static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008656 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008657 CONVERT_CHECKED(JSObject, object, args[0]);
8658 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008659 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008660 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008661 } else if (object->IsJSArray()) {
8662 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008663 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008664 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008665 }
8666}
8667
8668
lrn@chromium.org303ada72010-10-27 09:33:13 +00008669static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008670 HandleScope handle_scope;
8671
8672 ASSERT_EQ(3, args.length());
8673
ager@chromium.orgac091b72010-05-05 07:34:42 +00008674 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008675 Handle<Object> key1 = args.at<Object>(1);
8676 Handle<Object> key2 = args.at<Object>(2);
8677
8678 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008679 if (!key1->ToArrayIndex(&index1)
8680 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008681 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008682 }
8683
ager@chromium.orgac091b72010-05-05 07:34:42 +00008684 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8685 Handle<Object> tmp1 = GetElement(jsobject, index1);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008686 RETURN_IF_EMPTY_HANDLE(tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008687 Handle<Object> tmp2 = GetElement(jsobject, index2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008688 RETURN_IF_EMPTY_HANDLE(tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008689
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008690 RETURN_IF_EMPTY_HANDLE(SetElement(jsobject, index1, tmp2, kStrictMode));
8691 RETURN_IF_EMPTY_HANDLE(SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00008692
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008693 return Heap::undefined_value();
8694}
8695
8696
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008697// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008698// might have elements. Can either return keys (positive integers) or
8699// intervals (pair of a negative integer (-start-1) followed by a
8700// positive (length)) or undefined values.
8701// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008702static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008703 ASSERT(args.length() == 2);
8704 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008705 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008706 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008707 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008708 // Create an array and get all the keys into it, then remove all the
8709 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008710 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008711 int keys_length = keys->length();
8712 for (int i = 0; i < keys_length; i++) {
8713 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008714 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008715 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008716 // Zap invalid keys.
8717 keys->set_undefined(i);
8718 }
8719 }
8720 return *Factory::NewJSArrayWithElements(keys);
8721 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008722 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008723 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8724 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008725 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008726 uint32_t actual_length =
8727 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008728 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008729 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008730 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008731 single_interval->set(1, *length_object);
8732 return *Factory::NewJSArrayWithElements(single_interval);
8733 }
8734}
8735
8736
8737// DefineAccessor takes an optional final argument which is the
8738// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8739// to the way accessors are implemented, it is set for both the getter
8740// and setter on the first call to DefineAccessor and ignored on
8741// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008742static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008743 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8744 // Compute attributes.
8745 PropertyAttributes attributes = NONE;
8746 if (args.length() == 5) {
8747 CONVERT_CHECKED(Smi, attrs, args[4]);
8748 int value = attrs->value();
8749 // Only attribute bits should be set.
8750 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8751 attributes = static_cast<PropertyAttributes>(value);
8752 }
8753
8754 CONVERT_CHECKED(JSObject, obj, args[0]);
8755 CONVERT_CHECKED(String, name, args[1]);
8756 CONVERT_CHECKED(Smi, flag, args[2]);
8757 CONVERT_CHECKED(JSFunction, fun, args[3]);
8758 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8759}
8760
8761
lrn@chromium.org303ada72010-10-27 09:33:13 +00008762static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008763 ASSERT(args.length() == 3);
8764 CONVERT_CHECKED(JSObject, obj, args[0]);
8765 CONVERT_CHECKED(String, name, args[1]);
8766 CONVERT_CHECKED(Smi, flag, args[2]);
8767 return obj->LookupAccessor(name, flag->value() == 0);
8768}
8769
8770
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008771#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008772static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008773 ASSERT(args.length() == 0);
8774 return Execution::DebugBreakHelper();
8775}
8776
8777
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008778// Helper functions for wrapping and unwrapping stack frame ids.
8779static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008780 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008781 return Smi::FromInt(id >> 2);
8782}
8783
8784
8785static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8786 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8787}
8788
8789
8790// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008791// args[0]: debug event listener function to set or null or undefined for
8792// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008793// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008794static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008795 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008796 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8797 args[0]->IsUndefined() ||
8798 args[0]->IsNull());
8799 Handle<Object> callback = args.at<Object>(0);
8800 Handle<Object> data = args.at<Object>(1);
8801 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008802
8803 return Heap::undefined_value();
8804}
8805
8806
lrn@chromium.org303ada72010-10-27 09:33:13 +00008807static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008808 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008809 StackGuard::DebugBreak();
8810 return Heap::undefined_value();
8811}
8812
8813
lrn@chromium.org303ada72010-10-27 09:33:13 +00008814static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8815 LookupResult* result,
8816 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008817 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008818 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008819 case NORMAL:
8820 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008821 if (value->IsTheHole()) {
8822 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008823 }
8824 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008825 case FIELD:
8826 value =
8827 JSObject::cast(
8828 result->holder())->FastPropertyAt(result->GetFieldIndex());
8829 if (value->IsTheHole()) {
8830 return Heap::undefined_value();
8831 }
8832 return value;
8833 case CONSTANT_FUNCTION:
8834 return result->GetConstantFunction();
8835 case CALLBACKS: {
8836 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008837 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008838 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008839 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008840 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008841 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008842 ASSERT(maybe_value->IsException());
8843 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008844 Top::clear_pending_exception();
8845 if (caught_exception != NULL) {
8846 *caught_exception = true;
8847 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008848 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008849 }
8850 return value;
8851 } else {
8852 return Heap::undefined_value();
8853 }
8854 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008855 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008856 case MAP_TRANSITION:
8857 case CONSTANT_TRANSITION:
8858 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008859 return Heap::undefined_value();
8860 default:
8861 UNREACHABLE();
8862 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008863 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008864 return Heap::undefined_value();
8865}
8866
8867
ager@chromium.org32912102009-01-16 10:38:43 +00008868// Get debugger related details for an object property.
8869// args[0]: object holding property
8870// args[1]: name of the property
8871//
8872// The array returned contains the following information:
8873// 0: Property value
8874// 1: Property details
8875// 2: Property value is exception
8876// 3: Getter function if defined
8877// 4: Setter function if defined
8878// Items 2-4 are only filled if the property has either a getter or a setter
8879// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008880static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008881 HandleScope scope;
8882
8883 ASSERT(args.length() == 2);
8884
8885 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8886 CONVERT_ARG_CHECKED(String, name, 1);
8887
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008888 // Make sure to set the current context to the context before the debugger was
8889 // entered (if the debugger is entered). The reason for switching context here
8890 // is that for some property lookups (accessors and interceptors) callbacks
8891 // into the embedding application can occour, and the embedding application
8892 // could have the assumption that its own global context is the current
8893 // context and not some internal debugger context.
8894 SaveContext save;
8895 if (Debug::InDebugger()) {
8896 Top::set_context(*Debug::debugger_entry()->GetContext());
8897 }
8898
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008899 // Skip the global proxy as it has no properties and always delegates to the
8900 // real global object.
8901 if (obj->IsJSGlobalProxy()) {
8902 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8903 }
8904
8905
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008906 // Check if the name is trivially convertible to an index and get the element
8907 // if so.
8908 uint32_t index;
8909 if (name->AsArrayIndex(&index)) {
8910 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008911 Object* element_or_char;
8912 { MaybeObject* maybe_element_or_char =
8913 Runtime::GetElementOrCharAt(obj, index);
8914 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8915 return maybe_element_or_char;
8916 }
8917 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008918 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008919 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8920 return *Factory::NewJSArrayWithElements(details);
8921 }
8922
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008923 // Find the number of objects making up this.
8924 int length = LocalPrototypeChainLength(*obj);
8925
8926 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008927 Handle<JSObject> jsproto = obj;
8928 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008929 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008930 jsproto->LocalLookup(*name, &result);
8931 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008932 // LookupResult is not GC safe as it holds raw object pointers.
8933 // GC can happen later in this code so put the required fields into
8934 // local variables using handles when required for later use.
8935 PropertyType result_type = result.type();
8936 Handle<Object> result_callback_obj;
8937 if (result_type == CALLBACKS) {
8938 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8939 }
8940 Smi* property_details = result.GetPropertyDetails().AsSmi();
8941 // DebugLookupResultValue can cause GC so details from LookupResult needs
8942 // to be copied to handles before this.
8943 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008944 Object* raw_value;
8945 { MaybeObject* maybe_raw_value =
8946 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8947 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8948 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008949 Handle<Object> value(raw_value);
8950
8951 // If the callback object is a fixed array then it contains JavaScript
8952 // getter and/or setter.
8953 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8954 result_callback_obj->IsFixedArray();
8955 Handle<FixedArray> details =
8956 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8957 details->set(0, *value);
8958 details->set(1, property_details);
8959 if (hasJavaScriptAccessors) {
8960 details->set(2,
8961 caught_exception ? Heap::true_value()
8962 : Heap::false_value());
8963 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8964 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8965 }
8966
8967 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008968 }
8969 if (i < length - 1) {
8970 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8971 }
8972 }
8973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008974 return Heap::undefined_value();
8975}
8976
8977
lrn@chromium.org303ada72010-10-27 09:33:13 +00008978static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008979 HandleScope scope;
8980
8981 ASSERT(args.length() == 2);
8982
8983 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8984 CONVERT_ARG_CHECKED(String, name, 1);
8985
8986 LookupResult result;
8987 obj->Lookup(*name, &result);
8988 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008989 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008990 }
8991 return Heap::undefined_value();
8992}
8993
8994
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008995// Return the property type calculated from the property details.
8996// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008997static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008998 ASSERT(args.length() == 1);
8999 CONVERT_CHECKED(Smi, details, args[0]);
9000 PropertyType type = PropertyDetails(details).type();
9001 return Smi::FromInt(static_cast<int>(type));
9002}
9003
9004
9005// Return the property attribute calculated from the property details.
9006// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009007static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009008 ASSERT(args.length() == 1);
9009 CONVERT_CHECKED(Smi, details, args[0]);
9010 PropertyAttributes attributes = PropertyDetails(details).attributes();
9011 return Smi::FromInt(static_cast<int>(attributes));
9012}
9013
9014
9015// Return the property insertion index calculated from the property details.
9016// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009017static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009018 ASSERT(args.length() == 1);
9019 CONVERT_CHECKED(Smi, details, args[0]);
9020 int index = PropertyDetails(details).index();
9021 return Smi::FromInt(index);
9022}
9023
9024
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009025// Return property value from named interceptor.
9026// args[0]: object
9027// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00009028static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009029 HandleScope scope;
9030 ASSERT(args.length() == 2);
9031 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9032 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9033 CONVERT_ARG_CHECKED(String, name, 1);
9034
9035 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009036 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009037}
9038
9039
9040// Return element value from indexed interceptor.
9041// args[0]: object
9042// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00009043static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
9044 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009045 HandleScope scope;
9046 ASSERT(args.length() == 2);
9047 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9048 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9049 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9050
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009051 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009052}
9053
9054
lrn@chromium.org303ada72010-10-27 09:33:13 +00009055static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009056 ASSERT(args.length() >= 1);
9057 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009058 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009059 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009060 return Top::Throw(Heap::illegal_execution_state_symbol());
9061 }
9062
9063 return Heap::true_value();
9064}
9065
9066
lrn@chromium.org303ada72010-10-27 09:33:13 +00009067static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068 HandleScope scope;
9069 ASSERT(args.length() == 1);
9070
9071 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009072 Object* result;
9073 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9074 if (!maybe_result->ToObject(&result)) return maybe_result;
9075 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009076
9077 // Count all frames which are relevant to debugging stack trace.
9078 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009079 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009080 if (id == StackFrame::NO_ID) {
9081 // If there is no JavaScript stack frame count is 0.
9082 return Smi::FromInt(0);
9083 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009084 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
9085 return Smi::FromInt(n);
9086}
9087
9088
9089static const int kFrameDetailsFrameIdIndex = 0;
9090static const int kFrameDetailsReceiverIndex = 1;
9091static const int kFrameDetailsFunctionIndex = 2;
9092static const int kFrameDetailsArgumentCountIndex = 3;
9093static const int kFrameDetailsLocalCountIndex = 4;
9094static const int kFrameDetailsSourcePositionIndex = 5;
9095static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009096static const int kFrameDetailsAtReturnIndex = 7;
9097static const int kFrameDetailsDebuggerFrameIndex = 8;
9098static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009099
9100// Return an array with frame details
9101// args[0]: number: break id
9102// args[1]: number: frame index
9103//
9104// The array returned contains the following information:
9105// 0: Frame id
9106// 1: Receiver
9107// 2: Function
9108// 3: Argument count
9109// 4: Local count
9110// 5: Source position
9111// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009112// 7: Is at return
9113// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009114// Arguments name, value
9115// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009116// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00009117static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009118 HandleScope scope;
9119 ASSERT(args.length() == 2);
9120
9121 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009122 Object* check;
9123 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9124 if (!maybe_check->ToObject(&check)) return maybe_check;
9125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009126 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9127
9128 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00009129 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009130 if (id == StackFrame::NO_ID) {
9131 // If there are no JavaScript stack frames return undefined.
9132 return Heap::undefined_value();
9133 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009134 int count = 0;
9135 JavaScriptFrameIterator it(id);
9136 for (; !it.done(); it.Advance()) {
9137 if (count == index) break;
9138 count++;
9139 }
9140 if (it.done()) return Heap::undefined_value();
9141
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009142 bool is_optimized_frame =
9143 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
9144
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009145 // Traverse the saved contexts chain to find the active context for the
9146 // selected frame.
9147 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009148 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009149 save = save->prev();
9150 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009151 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009152
9153 // Get the frame id.
9154 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
9155
9156 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00009157 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009158
9159 // Check for constructor frame.
9160 bool constructor = it.frame()->IsConstructor();
9161
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009162 // Get scope info and read from it for local variable information.
9163 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009164 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009165 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009166
9167 // Get the context.
9168 Handle<Context> context(Context::cast(it.frame()->context()));
9169
9170 // Get the locals names and values into a temporary array.
9171 //
9172 // TODO(1240907): Hide compiler-introduced stack variables
9173 // (e.g. .result)? For users of the debugger, they will probably be
9174 // confusing.
9175 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009176
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009177 // Fill in the names of the locals.
9178 for (int i = 0; i < info.NumberOfLocals(); i++) {
9179 locals->set(i * 2, *info.LocalName(i));
9180 }
9181
9182 // Fill in the values of the locals.
9183 for (int i = 0; i < info.NumberOfLocals(); i++) {
9184 if (is_optimized_frame) {
9185 // If we are inspecting an optimized frame use undefined as the
9186 // value for all locals.
9187 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009188 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009189 // for locals in optimized frames.
9190 locals->set(i * 2 + 1, Heap::undefined_value());
9191 } else if (i < info.number_of_stack_slots()) {
9192 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009193 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9194 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009195 // Traverse the context chain to the function context as all local
9196 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009197 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009198 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009199 context = Handle<Context>(context->previous());
9200 }
9201 ASSERT(context->is_function_context());
9202 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009203 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009204 }
9205 }
9206
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009207 // Check whether this frame is positioned at return. If not top
9208 // frame or if the frame is optimized it cannot be at a return.
9209 bool at_return = false;
9210 if (!is_optimized_frame && index == 0) {
9211 at_return = Debug::IsBreakAtReturn(it.frame());
9212 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009213
9214 // If positioned just before return find the value to be returned and add it
9215 // to the frame information.
9216 Handle<Object> return_value = Factory::undefined_value();
9217 if (at_return) {
9218 StackFrameIterator it2;
9219 Address internal_frame_sp = NULL;
9220 while (!it2.done()) {
9221 if (it2.frame()->is_internal()) {
9222 internal_frame_sp = it2.frame()->sp();
9223 } else {
9224 if (it2.frame()->is_java_script()) {
9225 if (it2.frame()->id() == it.frame()->id()) {
9226 // The internal frame just before the JavaScript frame contains the
9227 // value to return on top. A debug break at return will create an
9228 // internal frame to store the return value (eax/rax/r0) before
9229 // entering the debug break exit frame.
9230 if (internal_frame_sp != NULL) {
9231 return_value =
9232 Handle<Object>(Memory::Object_at(internal_frame_sp));
9233 break;
9234 }
9235 }
9236 }
9237
9238 // Indicate that the previous frame was not an internal frame.
9239 internal_frame_sp = NULL;
9240 }
9241 it2.Advance();
9242 }
9243 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244
9245 // Now advance to the arguments adapter frame (if any). It contains all
9246 // the provided parameters whereas the function frame always have the number
9247 // of arguments matching the functions parameters. The rest of the
9248 // information (except for what is collected above) is the same.
9249 it.AdvanceToArgumentsFrame();
9250
9251 // Find the number of arguments to fill. At least fill the number of
9252 // parameters for the function and fill more if more parameters are provided.
9253 int argument_count = info.number_of_parameters();
9254 if (argument_count < it.frame()->GetProvidedParametersCount()) {
9255 argument_count = it.frame()->GetProvidedParametersCount();
9256 }
9257
9258 // Calculate the size of the result.
9259 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009260 2 * (argument_count + info.NumberOfLocals()) +
9261 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009262 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9263
9264 // Add the frame id.
9265 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9266
9267 // Add the function (same as in function frame).
9268 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9269
9270 // Add the arguments count.
9271 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9272
9273 // Add the locals count
9274 details->set(kFrameDetailsLocalCountIndex,
9275 Smi::FromInt(info.NumberOfLocals()));
9276
9277 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009278 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009279 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9280 } else {
9281 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
9282 }
9283
9284 // Add the constructor information.
9285 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
9286
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009287 // Add the at return information.
9288 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
9289
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009290 // Add information on whether this frame is invoked in the debugger context.
9291 details->set(kFrameDetailsDebuggerFrameIndex,
9292 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
9293
9294 // Fill the dynamic part.
9295 int details_index = kFrameDetailsFirstDynamicIndex;
9296
9297 // Add arguments name and value.
9298 for (int i = 0; i < argument_count; i++) {
9299 // Name of the argument.
9300 if (i < info.number_of_parameters()) {
9301 details->set(details_index++, *info.parameter_name(i));
9302 } else {
9303 details->set(details_index++, Heap::undefined_value());
9304 }
9305
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009306 // Parameter value. If we are inspecting an optimized frame, use
9307 // undefined as the value.
9308 //
9309 // TODO(3141533): We should be able to get the actual parameter
9310 // value for optimized frames.
9311 if (!is_optimized_frame &&
9312 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009313 details->set(details_index++, it.frame()->GetParameter(i));
9314 } else {
9315 details->set(details_index++, Heap::undefined_value());
9316 }
9317 }
9318
9319 // Add locals name and value from the temporary copy from the function frame.
9320 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9321 details->set(details_index++, locals->get(i));
9322 }
9323
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009324 // Add the value being returned.
9325 if (at_return) {
9326 details->set(details_index++, *return_value);
9327 }
9328
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009329 // Add the receiver (same as in function frame).
9330 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9331 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
9332 Handle<Object> receiver(it.frame()->receiver());
9333 if (!receiver->IsJSObject()) {
9334 // If the receiver is NOT a JSObject we have hit an optimization
9335 // where a value object is not converted into a wrapped JS objects.
9336 // To hide this optimization from the debugger, we wrap the receiver
9337 // by creating correct wrapper object based on the calling frame's
9338 // global context.
9339 it.Advance();
9340 Handle<Context> calling_frames_global_context(
9341 Context::cast(Context::cast(it.frame()->context())->global_context()));
9342 receiver = Factory::ToObject(receiver, calling_frames_global_context);
9343 }
9344 details->set(kFrameDetailsReceiverIndex, *receiver);
9345
9346 ASSERT_EQ(details_size, details_index);
9347 return *Factory::NewJSArrayWithElements(details);
9348}
9349
9350
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009351// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009352static bool CopyContextLocalsToScopeObject(
ager@chromium.orgb5737492010-07-15 09:29:43 +00009353 Handle<SerializedScopeInfo> serialized_scope_info,
9354 ScopeInfo<>& scope_info,
9355 Handle<Context> context,
9356 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009357 // Fill all context locals to the context extension.
9358 for (int i = Context::MIN_CONTEXT_SLOTS;
9359 i < scope_info.number_of_context_slots();
9360 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009361 int context_index = serialized_scope_info->ContextSlotIndex(
9362 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009363
9364 // Don't include the arguments shadow (.arguments) context variable.
9365 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009366 RETURN_IF_EMPTY_HANDLE_VALUE(
9367 SetProperty(scope_object,
9368 scope_info.context_slot_name(i),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009369 Handle<Object>(context->get(context_index)),
9370 NONE,
9371 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009372 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009373 }
9374 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009375
9376 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009377}
9378
9379
9380// Create a plain JSObject which materializes the local scope for the specified
9381// frame.
9382static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
9383 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009384 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009385 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9386 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009387
9388 // Allocate and initialize a JSObject with all the arguments, stack locals
9389 // heap locals and extension properties of the debugged function.
9390 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
9391
9392 // First fill all parameters.
9393 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009394 RETURN_IF_EMPTY_HANDLE_VALUE(
9395 SetProperty(local_scope,
9396 scope_info.parameter_name(i),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009397 Handle<Object>(frame->GetParameter(i)),
9398 NONE,
9399 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009400 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009401 }
9402
9403 // Second fill all stack locals.
9404 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009405 RETURN_IF_EMPTY_HANDLE_VALUE(
9406 SetProperty(local_scope,
9407 scope_info.stack_slot_name(i),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009408 Handle<Object>(frame->GetExpression(i)),
9409 NONE,
9410 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009411 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009412 }
9413
9414 // Third fill all context locals.
9415 Handle<Context> frame_context(Context::cast(frame->context()));
9416 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009417 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9418 function_context, local_scope)) {
9419 return Handle<JSObject>();
9420 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009421
9422 // Finally copy any properties from the function context extension. This will
9423 // be variables introduced by eval.
9424 if (function_context->closure() == *function) {
9425 if (function_context->has_extension() &&
9426 !function_context->IsGlobalContext()) {
9427 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009428 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009429 for (int i = 0; i < keys->length(); i++) {
9430 // Names of variables introduced by eval are strings.
9431 ASSERT(keys->get(i)->IsString());
9432 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009433 RETURN_IF_EMPTY_HANDLE_VALUE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009434 SetProperty(local_scope,
9435 key,
9436 GetProperty(ext, key),
9437 NONE,
9438 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009439 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009440 }
9441 }
9442 }
9443 return local_scope;
9444}
9445
9446
9447// Create a plain JSObject which materializes the closure content for the
9448// context.
9449static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
9450 ASSERT(context->is_function_context());
9451
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009452 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009453 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9454 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009455
9456 // Allocate and initialize a JSObject with all the content of theis function
9457 // closure.
9458 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
9459
9460 // Check whether the arguments shadow object exists.
9461 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00009462 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
9463 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009464 if (arguments_shadow_index >= 0) {
9465 // In this case all the arguments are available in the arguments shadow
9466 // object.
9467 Handle<JSObject> arguments_shadow(
9468 JSObject::cast(context->get(arguments_shadow_index)));
9469 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009470 // We don't expect exception-throwing getters on the arguments shadow.
9471 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009472 RETURN_IF_EMPTY_HANDLE_VALUE(
9473 SetProperty(closure_scope,
9474 scope_info.parameter_name(i),
9475 Handle<Object>(element),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009476 NONE,
9477 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009478 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009479 }
9480 }
9481
9482 // Fill all context locals to the context extension.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009483 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9484 context, closure_scope)) {
9485 return Handle<JSObject>();
9486 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009487
9488 // Finally copy any properties from the function context extension. This will
9489 // be variables introduced by eval.
9490 if (context->has_extension()) {
9491 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009492 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009493 for (int i = 0; i < keys->length(); i++) {
9494 // Names of variables introduced by eval are strings.
9495 ASSERT(keys->get(i)->IsString());
9496 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009497 RETURN_IF_EMPTY_HANDLE_VALUE(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009498 SetProperty(closure_scope,
9499 key,
9500 GetProperty(ext, key),
9501 NONE,
9502 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009503 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009504 }
9505 }
9506
9507 return closure_scope;
9508}
9509
9510
9511// Iterate over the actual scopes visible from a stack frame. All scopes are
9512// backed by an actual context except the local scope, which is inserted
9513// "artifically" in the context chain.
9514class ScopeIterator {
9515 public:
9516 enum ScopeType {
9517 ScopeTypeGlobal = 0,
9518 ScopeTypeLocal,
9519 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009520 ScopeTypeClosure,
9521 // Every catch block contains an implicit with block (its parameter is
9522 // a JSContextExtensionObject) that extends current scope with a variable
9523 // holding exception object. Such with blocks are treated as scopes of their
9524 // own type.
9525 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009526 };
9527
9528 explicit ScopeIterator(JavaScriptFrame* frame)
9529 : frame_(frame),
9530 function_(JSFunction::cast(frame->function())),
9531 context_(Context::cast(frame->context())),
9532 local_done_(false),
9533 at_local_(false) {
9534
9535 // Check whether the first scope is actually a local scope.
9536 if (context_->IsGlobalContext()) {
9537 // If there is a stack slot for .result then this local scope has been
9538 // created for evaluating top level code and it is not a real local scope.
9539 // Checking for the existence of .result seems fragile, but the scope info
9540 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009541 int index = function_->shared()->scope_info()->
9542 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009543 at_local_ = index < 0;
9544 } else if (context_->is_function_context()) {
9545 at_local_ = true;
9546 }
9547 }
9548
9549 // More scopes?
9550 bool Done() { return context_.is_null(); }
9551
9552 // Move to the next scope.
9553 void Next() {
9554 // If at a local scope mark the local scope as passed.
9555 if (at_local_) {
9556 at_local_ = false;
9557 local_done_ = true;
9558
9559 // If the current context is not associated with the local scope the
9560 // current context is the next real scope, so don't move to the next
9561 // context in this case.
9562 if (context_->closure() != *function_) {
9563 return;
9564 }
9565 }
9566
9567 // The global scope is always the last in the chain.
9568 if (context_->IsGlobalContext()) {
9569 context_ = Handle<Context>();
9570 return;
9571 }
9572
9573 // Move to the next context.
9574 if (context_->is_function_context()) {
9575 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9576 } else {
9577 context_ = Handle<Context>(context_->previous());
9578 }
9579
9580 // If passing the local scope indicate that the current scope is now the
9581 // local scope.
9582 if (!local_done_ &&
9583 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9584 at_local_ = true;
9585 }
9586 }
9587
9588 // Return the type of the current scope.
9589 int Type() {
9590 if (at_local_) {
9591 return ScopeTypeLocal;
9592 }
9593 if (context_->IsGlobalContext()) {
9594 ASSERT(context_->global()->IsGlobalObject());
9595 return ScopeTypeGlobal;
9596 }
9597 if (context_->is_function_context()) {
9598 return ScopeTypeClosure;
9599 }
9600 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009601 // Current scope is either an explicit with statement or a with statement
9602 // implicitely generated for a catch block.
9603 // If the extension object here is a JSContextExtensionObject then
9604 // current with statement is one frome a catch block otherwise it's a
9605 // regular with statement.
9606 if (context_->extension()->IsJSContextExtensionObject()) {
9607 return ScopeTypeCatch;
9608 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009609 return ScopeTypeWith;
9610 }
9611
9612 // Return the JavaScript object with the content of the current scope.
9613 Handle<JSObject> ScopeObject() {
9614 switch (Type()) {
9615 case ScopeIterator::ScopeTypeGlobal:
9616 return Handle<JSObject>(CurrentContext()->global());
9617 break;
9618 case ScopeIterator::ScopeTypeLocal:
9619 // Materialize the content of the local scope into a JSObject.
9620 return MaterializeLocalScope(frame_);
9621 break;
9622 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009623 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009624 // Return the with object.
9625 return Handle<JSObject>(CurrentContext()->extension());
9626 break;
9627 case ScopeIterator::ScopeTypeClosure:
9628 // Materialize the content of the closure scope into a JSObject.
9629 return MaterializeClosure(CurrentContext());
9630 break;
9631 }
9632 UNREACHABLE();
9633 return Handle<JSObject>();
9634 }
9635
9636 // Return the context for this scope. For the local context there might not
9637 // be an actual context.
9638 Handle<Context> CurrentContext() {
9639 if (at_local_ && context_->closure() != *function_) {
9640 return Handle<Context>();
9641 }
9642 return context_;
9643 }
9644
9645#ifdef DEBUG
9646 // Debug print of the content of the current scope.
9647 void DebugPrint() {
9648 switch (Type()) {
9649 case ScopeIterator::ScopeTypeGlobal:
9650 PrintF("Global:\n");
9651 CurrentContext()->Print();
9652 break;
9653
9654 case ScopeIterator::ScopeTypeLocal: {
9655 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009656 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009657 scope_info.Print();
9658 if (!CurrentContext().is_null()) {
9659 CurrentContext()->Print();
9660 if (CurrentContext()->has_extension()) {
9661 Handle<JSObject> extension =
9662 Handle<JSObject>(CurrentContext()->extension());
9663 if (extension->IsJSContextExtensionObject()) {
9664 extension->Print();
9665 }
9666 }
9667 }
9668 break;
9669 }
9670
9671 case ScopeIterator::ScopeTypeWith: {
9672 PrintF("With:\n");
9673 Handle<JSObject> extension =
9674 Handle<JSObject>(CurrentContext()->extension());
9675 extension->Print();
9676 break;
9677 }
9678
ager@chromium.orga1645e22009-09-09 19:27:10 +00009679 case ScopeIterator::ScopeTypeCatch: {
9680 PrintF("Catch:\n");
9681 Handle<JSObject> extension =
9682 Handle<JSObject>(CurrentContext()->extension());
9683 extension->Print();
9684 break;
9685 }
9686
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009687 case ScopeIterator::ScopeTypeClosure: {
9688 PrintF("Closure:\n");
9689 CurrentContext()->Print();
9690 if (CurrentContext()->has_extension()) {
9691 Handle<JSObject> extension =
9692 Handle<JSObject>(CurrentContext()->extension());
9693 if (extension->IsJSContextExtensionObject()) {
9694 extension->Print();
9695 }
9696 }
9697 break;
9698 }
9699
9700 default:
9701 UNREACHABLE();
9702 }
9703 PrintF("\n");
9704 }
9705#endif
9706
9707 private:
9708 JavaScriptFrame* frame_;
9709 Handle<JSFunction> function_;
9710 Handle<Context> context_;
9711 bool local_done_;
9712 bool at_local_;
9713
9714 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9715};
9716
9717
lrn@chromium.org303ada72010-10-27 09:33:13 +00009718static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009719 HandleScope scope;
9720 ASSERT(args.length() == 2);
9721
9722 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009723 Object* check;
9724 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9725 if (!maybe_check->ToObject(&check)) return maybe_check;
9726 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009727 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9728
9729 // Get the frame where the debugging is performed.
9730 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9731 JavaScriptFrameIterator it(id);
9732 JavaScriptFrame* frame = it.frame();
9733
9734 // Count the visible scopes.
9735 int n = 0;
9736 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9737 n++;
9738 }
9739
9740 return Smi::FromInt(n);
9741}
9742
9743
9744static const int kScopeDetailsTypeIndex = 0;
9745static const int kScopeDetailsObjectIndex = 1;
9746static const int kScopeDetailsSize = 2;
9747
9748// Return an array with scope details
9749// args[0]: number: break id
9750// args[1]: number: frame index
9751// args[2]: number: scope index
9752//
9753// The array returned contains the following information:
9754// 0: Scope type
9755// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009756static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009757 HandleScope scope;
9758 ASSERT(args.length() == 3);
9759
9760 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009761 Object* check;
9762 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9763 if (!maybe_check->ToObject(&check)) return maybe_check;
9764 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009765 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9766 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9767
9768 // Get the frame where the debugging is performed.
9769 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9770 JavaScriptFrameIterator frame_it(id);
9771 JavaScriptFrame* frame = frame_it.frame();
9772
9773 // Find the requested scope.
9774 int n = 0;
9775 ScopeIterator it(frame);
9776 for (; !it.Done() && n < index; it.Next()) {
9777 n++;
9778 }
9779 if (it.Done()) {
9780 return Heap::undefined_value();
9781 }
9782
9783 // Calculate the size of the result.
9784 int details_size = kScopeDetailsSize;
9785 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9786
9787 // Fill in scope details.
9788 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009789 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009790 RETURN_IF_EMPTY_HANDLE(scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009791 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009792
9793 return *Factory::NewJSArrayWithElements(details);
9794}
9795
9796
lrn@chromium.org303ada72010-10-27 09:33:13 +00009797static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009798 HandleScope scope;
9799 ASSERT(args.length() == 0);
9800
9801#ifdef DEBUG
9802 // Print the scopes for the top frame.
9803 StackFrameLocator locator;
9804 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9805 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9806 it.DebugPrint();
9807 }
9808#endif
9809 return Heap::undefined_value();
9810}
9811
9812
lrn@chromium.org303ada72010-10-27 09:33:13 +00009813static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009814 HandleScope scope;
9815 ASSERT(args.length() == 1);
9816
9817 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009818 Object* result;
9819 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9820 if (!maybe_result->ToObject(&result)) return maybe_result;
9821 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009822
9823 // Count all archived V8 threads.
9824 int n = 0;
9825 for (ThreadState* thread = ThreadState::FirstInUse();
9826 thread != NULL;
9827 thread = thread->Next()) {
9828 n++;
9829 }
9830
9831 // Total number of threads is current thread and archived threads.
9832 return Smi::FromInt(n + 1);
9833}
9834
9835
9836static const int kThreadDetailsCurrentThreadIndex = 0;
9837static const int kThreadDetailsThreadIdIndex = 1;
9838static const int kThreadDetailsSize = 2;
9839
9840// Return an array with thread details
9841// args[0]: number: break id
9842// args[1]: number: thread index
9843//
9844// The array returned contains the following information:
9845// 0: Is current thread?
9846// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009847static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009848 HandleScope scope;
9849 ASSERT(args.length() == 2);
9850
9851 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009852 Object* check;
9853 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9854 if (!maybe_check->ToObject(&check)) return maybe_check;
9855 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009856 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9857
9858 // Allocate array for result.
9859 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9860
9861 // Thread index 0 is current thread.
9862 if (index == 0) {
9863 // Fill the details.
9864 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9865 details->set(kThreadDetailsThreadIdIndex,
9866 Smi::FromInt(ThreadManager::CurrentId()));
9867 } else {
9868 // Find the thread with the requested index.
9869 int n = 1;
9870 ThreadState* thread = ThreadState::FirstInUse();
9871 while (index != n && thread != NULL) {
9872 thread = thread->Next();
9873 n++;
9874 }
9875 if (thread == NULL) {
9876 return Heap::undefined_value();
9877 }
9878
9879 // Fill the details.
9880 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9881 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9882 }
9883
9884 // Convert to JS array and return.
9885 return *Factory::NewJSArrayWithElements(details);
9886}
9887
9888
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009889// Sets the disable break state
9890// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009891static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009892 HandleScope scope;
9893 ASSERT(args.length() == 1);
9894 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9895 Debug::set_disable_break(disable_break);
9896 return Heap::undefined_value();
9897}
9898
9899
lrn@chromium.org303ada72010-10-27 09:33:13 +00009900static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009901 HandleScope scope;
9902 ASSERT(args.length() == 1);
9903
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009904 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9905 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009906 // Find the number of break points
9907 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9908 if (break_locations->IsUndefined()) return Heap::undefined_value();
9909 // Return array as JS array
9910 return *Factory::NewJSArrayWithElements(
9911 Handle<FixedArray>::cast(break_locations));
9912}
9913
9914
9915// Set a break point in a function
9916// args[0]: function
9917// args[1]: number: break source position (within the function source)
9918// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009919static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009920 HandleScope scope;
9921 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009922 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9923 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009924 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9925 RUNTIME_ASSERT(source_position >= 0);
9926 Handle<Object> break_point_object_arg = args.at<Object>(2);
9927
9928 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009929 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009930
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009931 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009932}
9933
9934
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009935Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9936 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009937 // Iterate the heap looking for SharedFunctionInfo generated from the
9938 // script. The inner most SharedFunctionInfo containing the source position
9939 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009940 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009941 // which is found is not compiled it is compiled and the heap is iterated
9942 // again as the compilation might create inner functions from the newly
9943 // compiled function and the actual requested break point might be in one of
9944 // these functions.
9945 bool done = false;
9946 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009947 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009948 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009949 while (!done) {
9950 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009951 for (HeapObject* obj = iterator.next();
9952 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009953 if (obj->IsSharedFunctionInfo()) {
9954 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9955 if (shared->script() == *script) {
9956 // If the SharedFunctionInfo found has the requested script data and
9957 // contains the source position it is a candidate.
9958 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009959 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009960 start_position = shared->start_position();
9961 }
9962 if (start_position <= position &&
9963 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009964 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009965 // candidate this is the new candidate.
9966 if (target.is_null()) {
9967 target_start_position = start_position;
9968 target = shared;
9969 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009970 if (target_start_position == start_position &&
9971 shared->end_position() == target->end_position()) {
9972 // If a top-level function contain only one function
9973 // declartion the source for the top-level and the function is
9974 // the same. In that case prefer the non top-level function.
9975 if (!shared->is_toplevel()) {
9976 target_start_position = start_position;
9977 target = shared;
9978 }
9979 } else if (target_start_position <= start_position &&
9980 shared->end_position() <= target->end_position()) {
9981 // This containment check includes equality as a function inside
9982 // a top-level function can share either start or end position
9983 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009984 target_start_position = start_position;
9985 target = shared;
9986 }
9987 }
9988 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009989 }
9990 }
9991 }
9992
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009993 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009994 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009995 }
9996
9997 // If the candidate found is compiled we are done. NOTE: when lazy
9998 // compilation of inner functions is introduced some additional checking
9999 // needs to be done here to compile inner functions.
10000 done = target->is_compiled();
10001 if (!done) {
10002 // If the candidate is not compiled compile it to reveal any inner
10003 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010004 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010005 }
10006 }
10007
10008 return *target;
10009}
10010
10011
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010012// Changes the state of a break point in a script and returns source position
10013// where break point was set. NOTE: Regarding performance see the NOTE for
10014// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010015// args[0]: script to set break point in
10016// args[1]: number: break source position (within the script source)
10017// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +000010018static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010019 HandleScope scope;
10020 ASSERT(args.length() == 3);
10021 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10022 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10023 RUNTIME_ASSERT(source_position >= 0);
10024 Handle<Object> break_point_object_arg = args.at<Object>(2);
10025
10026 // Get the script from the script wrapper.
10027 RUNTIME_ASSERT(wrapper->value()->IsScript());
10028 Handle<Script> script(Script::cast(wrapper->value()));
10029
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010030 Object* result = Runtime::FindSharedFunctionInfoInScript(
10031 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010032 if (!result->IsUndefined()) {
10033 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10034 // Find position within function. The script position might be before the
10035 // source position of the first function.
10036 int position;
10037 if (shared->start_position() > source_position) {
10038 position = 0;
10039 } else {
10040 position = source_position - shared->start_position();
10041 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010042 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
10043 position += shared->start_position();
10044 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010045 }
10046 return Heap::undefined_value();
10047}
10048
10049
10050// Clear a break point
10051// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +000010052static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010053 HandleScope scope;
10054 ASSERT(args.length() == 1);
10055 Handle<Object> break_point_object_arg = args.at<Object>(0);
10056
10057 // Clear break point.
10058 Debug::ClearBreakPoint(break_point_object_arg);
10059
10060 return Heap::undefined_value();
10061}
10062
10063
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010064// Change the state of break on exceptions.
10065// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10066// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010067static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010068 HandleScope scope;
10069 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010070 RUNTIME_ASSERT(args[0]->IsNumber());
10071 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010072
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010073 // If the number doesn't match an enum value, the ChangeBreakOnException
10074 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010075 ExceptionBreakType type =
10076 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010077 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010078 Debug::ChangeBreakOnException(type, enable);
10079 return Heap::undefined_value();
10080}
10081
10082
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010083// Returns the state of break on exceptions
10084// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +000010085static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010086 HandleScope scope;
10087 ASSERT(args.length() == 1);
10088 RUNTIME_ASSERT(args[0]->IsNumber());
10089
10090 ExceptionBreakType type =
10091 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
10092 bool result = Debug::IsBreakOnException(type);
10093 return Smi::FromInt(result);
10094}
10095
10096
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010097// Prepare for stepping
10098// args[0]: break id for checking execution state
10099// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010100// args[2]: number of times to perform the step, for step out it is the number
10101// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010102static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010103 HandleScope scope;
10104 ASSERT(args.length() == 3);
10105 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010106 Object* check;
10107 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
10108 if (!maybe_check->ToObject(&check)) return maybe_check;
10109 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010110 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
10111 return Top::Throw(Heap::illegal_argument_symbol());
10112 }
10113
10114 // Get the step action and check validity.
10115 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10116 if (step_action != StepIn &&
10117 step_action != StepNext &&
10118 step_action != StepOut &&
10119 step_action != StepInMin &&
10120 step_action != StepMin) {
10121 return Top::Throw(Heap::illegal_argument_symbol());
10122 }
10123
10124 // Get the number of steps.
10125 int step_count = NumberToInt32(args[2]);
10126 if (step_count < 1) {
10127 return Top::Throw(Heap::illegal_argument_symbol());
10128 }
10129
ager@chromium.orga1645e22009-09-09 19:27:10 +000010130 // Clear all current stepping setup.
10131 Debug::ClearStepping();
10132
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010133 // Prepare step.
10134 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
10135 return Heap::undefined_value();
10136}
10137
10138
10139// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010140static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010141 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010142 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010143 Debug::ClearStepping();
10144 return Heap::undefined_value();
10145}
10146
10147
10148// Creates a copy of the with context chain. The copy of the context chain is
10149// is linked to the function context supplied.
10150static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10151 Handle<Context> function_context) {
10152 // At the bottom of the chain. Return the function context to link to.
10153 if (context_chain->is_function_context()) {
10154 return function_context;
10155 }
10156
10157 // Recursively copy the with contexts.
10158 Handle<Context> previous(context_chain->previous());
10159 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010160 Handle<Context> context = CopyWithContextChain(function_context, previous);
10161 return Factory::NewWithContext(context,
10162 extension,
10163 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010164}
10165
10166
10167// Helper function to find or create the arguments object for
10168// Runtime_DebugEvaluate.
10169static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
10170 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010171 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010172 const ScopeInfo<>* sinfo,
10173 Handle<Context> function_context) {
10174 // Try to find the value of 'arguments' to pass as parameter. If it is not
10175 // found (that is the debugged function does not reference 'arguments' and
10176 // does not support eval) then create an 'arguments' object.
10177 int index;
10178 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010179 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010180 if (index != -1) {
10181 return Handle<Object>(frame->GetExpression(index));
10182 }
10183 }
10184
10185 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010186 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010187 if (index != -1) {
10188 return Handle<Object>(function_context->get(index));
10189 }
10190 }
10191
10192 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010193 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
10194 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010195
10196 AssertNoAllocation no_gc;
10197 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010198 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010199 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010200 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010201 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010202 return arguments;
10203}
10204
10205
10206// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010207// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010208// extension part has all the parameters and locals of the function on the
10209// stack frame. A function which calls eval with the code to evaluate is then
10210// compiled in this context and called in this context. As this context
10211// replaces the context of the function on the stack frame a new (empty)
10212// function is created as well to be used as the closure for the context.
10213// This function and the context acts as replacements for the function on the
10214// stack frame presenting the same view of the values of parameters and
10215// local variables as if the piece of JavaScript was evaluated at the point
10216// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010217static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010218 HandleScope scope;
10219
10220 // Check the execution state and decode arguments frame and source to be
10221 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010222 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010223 Object* check_result;
10224 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10225 if (!maybe_check_result->ToObject(&check_result)) {
10226 return maybe_check_result;
10227 }
10228 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010229 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10230 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010231 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010232 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010233
10234 // Handle the processing of break.
10235 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010236
10237 // Get the frame where the debugging is performed.
10238 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10239 JavaScriptFrameIterator it(id);
10240 JavaScriptFrame* frame = it.frame();
10241 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010242 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010243 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010244
10245 // Traverse the saved contexts chain to find the active context for the
10246 // selected frame.
10247 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010248 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010249 save = save->prev();
10250 }
10251 ASSERT(save != NULL);
10252 SaveContext savex;
10253 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254
10255 // Create the (empty) function replacing the function on the stack frame for
10256 // the purpose of evaluating in the context created below. It is important
10257 // that this function does not describe any parameters and local variables
10258 // in the context. If it does then this will cause problems with the lookup
10259 // in Context::Lookup, where context slots for parameters and local variables
10260 // are looked at before the extension object.
10261 Handle<JSFunction> go_between =
10262 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
10263 go_between->set_context(function->context());
10264#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010265 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010266 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10267 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10268#endif
10269
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010270 // Materialize the content of the local scope into a JSObject.
10271 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010272 RETURN_IF_EMPTY_HANDLE(local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010273
10274 // Allocate a new context for the debug evaluation and set the extension
10275 // object build.
10276 Handle<Context> context =
10277 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010278 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010279 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010280 Handle<Context> frame_context(Context::cast(frame->context()));
10281 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010282 context = CopyWithContextChain(frame_context, context);
10283
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010284 if (additional_context->IsJSObject()) {
10285 context = Factory::NewWithContext(context,
10286 Handle<JSObject>::cast(additional_context), false);
10287 }
10288
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010289 // Wrap the evaluation statement in a new function compiled in the newly
10290 // created context. The function has one parameter which has to be called
10291 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010292 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010293 // function(arguments,__source__) {return eval(__source__);}
10294 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010295 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010296 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010297 Handle<String> function_source =
10298 Factory::NewStringFromAscii(Vector<const char>(source_str,
10299 source_str_length));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010300
10301 // Currently, the eval code will be executed in non-strict mode,
10302 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010303 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010304 Compiler::CompileEval(function_source,
10305 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010306 context->IsGlobalContext(),
10307 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010308 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010309 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010310 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010311
10312 // Invoke the result of the compilation to get the evaluation function.
10313 bool has_pending_exception;
10314 Handle<Object> receiver(frame->receiver());
10315 Handle<Object> evaluation_function =
10316 Execution::Call(compiled_function, receiver, 0, NULL,
10317 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010318 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010319
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010320 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
10321 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010322
10323 // Invoke the evaluation function and return the result.
10324 const int argc = 2;
10325 Object** argv[argc] = { arguments.location(),
10326 Handle<Object>::cast(source).location() };
10327 Handle<Object> result =
10328 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10329 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010330 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010331
10332 // Skip the global proxy as it has no properties and always delegates to the
10333 // real global object.
10334 if (result->IsJSGlobalProxy()) {
10335 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10336 }
10337
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010338 return *result;
10339}
10340
10341
lrn@chromium.org303ada72010-10-27 09:33:13 +000010342static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010343 HandleScope scope;
10344
10345 // Check the execution state and decode arguments frame and source to be
10346 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010347 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010348 Object* check_result;
10349 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10350 if (!maybe_check_result->ToObject(&check_result)) {
10351 return maybe_check_result;
10352 }
10353 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010354 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010355 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010356 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010357
10358 // Handle the processing of break.
10359 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010360
10361 // Enter the top context from before the debugger was invoked.
10362 SaveContext save;
10363 SaveContext* top = &save;
10364 while (top != NULL && *top->context() == *Debug::debug_context()) {
10365 top = top->prev();
10366 }
10367 if (top != NULL) {
10368 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010369 }
10370
10371 // Get the global context now set to the top context from before the
10372 // debugger was invoked.
10373 Handle<Context> context = Top::global_context();
10374
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010375 bool is_global = true;
10376
10377 if (additional_context->IsJSObject()) {
10378 // Create a function context first, than put 'with' context on top of it.
10379 Handle<JSFunction> go_between = Factory::NewFunction(
10380 Factory::empty_string(), Factory::undefined_value());
10381 go_between->set_context(*context);
10382 context =
10383 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
10384 context->set_extension(JSObject::cast(*additional_context));
10385 is_global = false;
10386 }
10387
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010388 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010389 // Currently, the eval code will be executed in non-strict mode,
10390 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010391 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010392 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010393 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010394 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010395 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
10396 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010397
10398 // Invoke the result of the compilation to get the evaluation function.
10399 bool has_pending_exception;
10400 Handle<Object> receiver = Top::global();
10401 Handle<Object> result =
10402 Execution::Call(compiled_function, receiver, 0, NULL,
10403 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010404 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010405 return *result;
10406}
10407
10408
lrn@chromium.org303ada72010-10-27 09:33:13 +000010409static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010410 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010411 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010412
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010413 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010414 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010415
10416 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010417 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010418 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10419 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10420 // because using
10421 // instances->set(i, *GetScriptWrapper(script))
10422 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10423 // already have deferenced the instances handle.
10424 Handle<JSValue> wrapper = GetScriptWrapper(script);
10425 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010426 }
10427
10428 // Return result as a JS array.
10429 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
10430 Handle<JSArray>::cast(result)->SetContent(*instances);
10431 return *result;
10432}
10433
10434
10435// Helper function used by Runtime_DebugReferencedBy below.
10436static int DebugReferencedBy(JSObject* target,
10437 Object* instance_filter, int max_references,
10438 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010439 JSFunction* arguments_function) {
10440 NoHandleAllocation ha;
10441 AssertNoAllocation no_alloc;
10442
10443 // Iterate the heap.
10444 int count = 0;
10445 JSObject* last = NULL;
10446 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010447 HeapObject* heap_obj = NULL;
10448 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010449 (max_references == 0 || count < max_references)) {
10450 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010451 if (heap_obj->IsJSObject()) {
10452 // Skip context extension objects and argument arrays as these are
10453 // checked in the context of functions using them.
10454 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010455 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010456 obj->map()->constructor() == arguments_function) {
10457 continue;
10458 }
10459
10460 // Check if the JS object has a reference to the object looked for.
10461 if (obj->ReferencesObject(target)) {
10462 // Check instance filter if supplied. This is normally used to avoid
10463 // references from mirror objects (see Runtime_IsInPrototypeChain).
10464 if (!instance_filter->IsUndefined()) {
10465 Object* V = obj;
10466 while (true) {
10467 Object* prototype = V->GetPrototype();
10468 if (prototype->IsNull()) {
10469 break;
10470 }
10471 if (instance_filter == prototype) {
10472 obj = NULL; // Don't add this object.
10473 break;
10474 }
10475 V = prototype;
10476 }
10477 }
10478
10479 if (obj != NULL) {
10480 // Valid reference found add to instance array if supplied an update
10481 // count.
10482 if (instances != NULL && count < instances_size) {
10483 instances->set(count, obj);
10484 }
10485 last = obj;
10486 count++;
10487 }
10488 }
10489 }
10490 }
10491
10492 // Check for circular reference only. This can happen when the object is only
10493 // referenced from mirrors and has a circular reference in which case the
10494 // object is not really alive and would have been garbage collected if not
10495 // referenced from the mirror.
10496 if (count == 1 && last == target) {
10497 count = 0;
10498 }
10499
10500 // Return the number of referencing objects found.
10501 return count;
10502}
10503
10504
10505// Scan the heap for objects with direct references to an object
10506// args[0]: the object to find references to
10507// args[1]: constructor function for instances to exclude (Mirror)
10508// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010509static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010510 ASSERT(args.length() == 3);
10511
10512 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010513 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010514
10515 // Check parameters.
10516 CONVERT_CHECKED(JSObject, target, args[0]);
10517 Object* instance_filter = args[1];
10518 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10519 instance_filter->IsJSObject());
10520 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10521 RUNTIME_ASSERT(max_references >= 0);
10522
10523 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010524 JSObject* arguments_boilerplate =
10525 Top::context()->global_context()->arguments_boilerplate();
10526 JSFunction* arguments_function =
10527 JSFunction::cast(arguments_boilerplate->map()->constructor());
10528
10529 // Get the number of referencing objects.
10530 int count;
10531 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010532 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010533
10534 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010535 Object* object;
10536 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10537 if (!maybe_object->ToObject(&object)) return maybe_object;
10538 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010539 FixedArray* instances = FixedArray::cast(object);
10540
10541 // Fill the referencing objects.
10542 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010543 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010544
10545 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010546 Object* result;
10547 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10548 Top::context()->global_context()->array_function());
10549 if (!maybe_result->ToObject(&result)) return maybe_result;
10550 }
10551 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010552 return result;
10553}
10554
10555
10556// Helper function used by Runtime_DebugConstructedBy below.
10557static int DebugConstructedBy(JSFunction* constructor, int max_references,
10558 FixedArray* instances, int instances_size) {
10559 AssertNoAllocation no_alloc;
10560
10561 // Iterate the heap.
10562 int count = 0;
10563 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010564 HeapObject* heap_obj = NULL;
10565 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010566 (max_references == 0 || count < max_references)) {
10567 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010568 if (heap_obj->IsJSObject()) {
10569 JSObject* obj = JSObject::cast(heap_obj);
10570 if (obj->map()->constructor() == constructor) {
10571 // Valid reference found add to instance array if supplied an update
10572 // count.
10573 if (instances != NULL && count < instances_size) {
10574 instances->set(count, obj);
10575 }
10576 count++;
10577 }
10578 }
10579 }
10580
10581 // Return the number of referencing objects found.
10582 return count;
10583}
10584
10585
10586// Scan the heap for objects constructed by a specific function.
10587// args[0]: the constructor to find instances of
10588// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010589static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010590 ASSERT(args.length() == 2);
10591
10592 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010593 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594
10595 // Check parameters.
10596 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10597 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10598 RUNTIME_ASSERT(max_references >= 0);
10599
10600 // Get the number of referencing objects.
10601 int count;
10602 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10603
10604 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010605 Object* object;
10606 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10607 if (!maybe_object->ToObject(&object)) return maybe_object;
10608 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609 FixedArray* instances = FixedArray::cast(object);
10610
10611 // Fill the referencing objects.
10612 count = DebugConstructedBy(constructor, max_references, instances, count);
10613
10614 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010615 Object* result;
10616 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10617 Top::context()->global_context()->array_function());
10618 if (!maybe_result->ToObject(&result)) return maybe_result;
10619 }
10620 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010621 return result;
10622}
10623
10624
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010625// Find the effective prototype object as returned by __proto__.
10626// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010627static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010628 ASSERT(args.length() == 1);
10629
10630 CONVERT_CHECKED(JSObject, obj, args[0]);
10631
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010632 // Use the __proto__ accessor.
10633 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010634}
10635
10636
lrn@chromium.org303ada72010-10-27 09:33:13 +000010637static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010638 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010639 CPU::DebugBreak();
10640 return Heap::undefined_value();
10641}
10642
10643
lrn@chromium.org303ada72010-10-27 09:33:13 +000010644static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010645#ifdef DEBUG
10646 HandleScope scope;
10647 ASSERT(args.length() == 1);
10648 // Get the function and make sure it is compiled.
10649 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010650 Handle<SharedFunctionInfo> shared(func->shared());
10651 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010652 return Failure::Exception();
10653 }
10654 func->code()->PrintLn();
10655#endif // DEBUG
10656 return Heap::undefined_value();
10657}
ager@chromium.org9085a012009-05-11 19:22:57 +000010658
10659
lrn@chromium.org303ada72010-10-27 09:33:13 +000010660static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010661#ifdef DEBUG
10662 HandleScope scope;
10663 ASSERT(args.length() == 1);
10664 // Get the function and make sure it is compiled.
10665 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010666 Handle<SharedFunctionInfo> shared(func->shared());
10667 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010668 return Failure::Exception();
10669 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010670 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010671#endif // DEBUG
10672 return Heap::undefined_value();
10673}
10674
10675
lrn@chromium.org303ada72010-10-27 09:33:13 +000010676static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010677 NoHandleAllocation ha;
10678 ASSERT(args.length() == 1);
10679
10680 CONVERT_CHECKED(JSFunction, f, args[0]);
10681 return f->shared()->inferred_name();
10682}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010683
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010684
10685static int FindSharedFunctionInfosForScript(Script* script,
10686 FixedArray* buffer) {
10687 AssertNoAllocation no_allocations;
10688
10689 int counter = 0;
10690 int buffer_size = buffer->length();
10691 HeapIterator iterator;
10692 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10693 ASSERT(obj != NULL);
10694 if (!obj->IsSharedFunctionInfo()) {
10695 continue;
10696 }
10697 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10698 if (shared->script() != script) {
10699 continue;
10700 }
10701 if (counter < buffer_size) {
10702 buffer->set(counter, shared);
10703 }
10704 counter++;
10705 }
10706 return counter;
10707}
10708
10709// For a script finds all SharedFunctionInfo's in the heap that points
10710// to this script. Returns JSArray of SharedFunctionInfo wrapped
10711// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010712static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010713 Arguments args) {
10714 ASSERT(args.length() == 1);
10715 HandleScope scope;
10716 CONVERT_CHECKED(JSValue, script_value, args[0]);
10717
10718 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10719
10720 const int kBufferSize = 32;
10721
10722 Handle<FixedArray> array;
10723 array = Factory::NewFixedArray(kBufferSize);
10724 int number = FindSharedFunctionInfosForScript(*script, *array);
10725 if (number > kBufferSize) {
10726 array = Factory::NewFixedArray(number);
10727 FindSharedFunctionInfosForScript(*script, *array);
10728 }
10729
10730 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10731 result->set_length(Smi::FromInt(number));
10732
10733 LiveEdit::WrapSharedFunctionInfos(result);
10734
10735 return *result;
10736}
10737
10738// For a script calculates compilation information about all its functions.
10739// The script source is explicitly specified by the second argument.
10740// The source of the actual script is not used, however it is important that
10741// all generated code keeps references to this particular instance of script.
10742// Returns a JSArray of compilation infos. The array is ordered so that
10743// each function with all its descendant is always stored in a continues range
10744// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010745static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010746 ASSERT(args.length() == 2);
10747 HandleScope scope;
10748 CONVERT_CHECKED(JSValue, script, args[0]);
10749 CONVERT_ARG_CHECKED(String, source, 1);
10750 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10751
10752 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10753
10754 if (Top::has_pending_exception()) {
10755 return Failure::Exception();
10756 }
10757
10758 return result;
10759}
10760
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010761// Changes the source of the script to a new_source.
10762// If old_script_name is provided (i.e. is a String), also creates a copy of
10763// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010764static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010765 ASSERT(args.length() == 3);
10766 HandleScope scope;
10767 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10768 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010769 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010770
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010771 CONVERT_CHECKED(Script, original_script_pointer,
10772 original_script_value->value());
10773 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010774
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010775 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10776 new_source,
10777 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010778
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010779 if (old_script->IsScript()) {
10780 Handle<Script> script_handle(Script::cast(old_script));
10781 return *(GetScriptWrapper(script_handle));
10782 } else {
10783 return Heap::null_value();
10784 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010785}
10786
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010787
10788static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10789 ASSERT(args.length() == 1);
10790 HandleScope scope;
10791 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10792 return LiveEdit::FunctionSourceUpdated(shared_info);
10793}
10794
10795
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010796// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010797static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010798 ASSERT(args.length() == 2);
10799 HandleScope scope;
10800 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10801 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10802
ager@chromium.orgac091b72010-05-05 07:34:42 +000010803 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010804}
10805
10806// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010807static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010808 ASSERT(args.length() == 2);
10809 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010810 Handle<Object> function_object(args[0]);
10811 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010812
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010813 if (function_object->IsJSValue()) {
10814 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10815 if (script_object->IsJSValue()) {
10816 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10817 script_object = Handle<Object>(script);
10818 }
10819
10820 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10821 } else {
10822 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10823 // and we check it in this function.
10824 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010825
10826 return Heap::undefined_value();
10827}
10828
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010829
10830// In a code of a parent function replaces original function as embedded object
10831// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010832static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010833 ASSERT(args.length() == 3);
10834 HandleScope scope;
10835
10836 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10837 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10838 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10839
10840 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10841 subst_wrapper);
10842
10843 return Heap::undefined_value();
10844}
10845
10846
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010847// Updates positions of a shared function info (first parameter) according
10848// to script source change. Text change is described in second parameter as
10849// array of groups of 3 numbers:
10850// (change_begin, change_end, change_end_new_position).
10851// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010852static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010853 ASSERT(args.length() == 2);
10854 HandleScope scope;
10855 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10856 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10857
ager@chromium.orgac091b72010-05-05 07:34:42 +000010858 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010859}
10860
10861
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010862// For array of SharedFunctionInfo's (each wrapped in JSValue)
10863// checks that none of them have activations on stacks (of any thread).
10864// Returns array of the same length with corresponding results of
10865// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010866static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010867 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010868 HandleScope scope;
10869 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010870 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010871
ager@chromium.org357bf652010-04-12 11:30:10 +000010872 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010873}
10874
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010875// Compares 2 strings line-by-line, then token-wise and returns diff in form
10876// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
10877// of diff chunks.
10878static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010879 ASSERT(args.length() == 2);
10880 HandleScope scope;
10881 CONVERT_ARG_CHECKED(String, s1, 0);
10882 CONVERT_ARG_CHECKED(String, s2, 1);
10883
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010884 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010885}
10886
10887
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010888
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010889// A testing entry. Returns statement position which is the closest to
10890// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010891static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010892 ASSERT(args.length() == 2);
10893 HandleScope scope;
10894 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10895 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10896
10897 Handle<Code> code(function->code());
10898
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010899 if (code->kind() != Code::FUNCTION &&
10900 code->kind() != Code::OPTIMIZED_FUNCTION) {
10901 return Heap::undefined_value();
10902 }
10903
10904 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010905 int closest_pc = 0;
10906 int distance = kMaxInt;
10907 while (!it.done()) {
10908 int statement_position = static_cast<int>(it.rinfo()->data());
10909 // Check if this break point is closer that what was previously found.
10910 if (source_position <= statement_position &&
10911 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010912 closest_pc =
10913 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010914 distance = statement_position - source_position;
10915 // Check whether we can't get any closer.
10916 if (distance == 0) break;
10917 }
10918 it.next();
10919 }
10920
10921 return Smi::FromInt(closest_pc);
10922}
10923
10924
ager@chromium.org357bf652010-04-12 11:30:10 +000010925// Calls specified function with or without entering the debugger.
10926// This is used in unit tests to run code as if debugger is entered or simply
10927// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010928static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010929 ASSERT(args.length() == 2);
10930 HandleScope scope;
10931 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10932 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10933
10934 Handle<Object> result;
10935 bool pending_exception;
10936 {
10937 if (without_debugger) {
10938 result = Execution::Call(function, Top::global(), 0, NULL,
10939 &pending_exception);
10940 } else {
10941 EnterDebugger enter_debugger;
10942 result = Execution::Call(function, Top::global(), 0, NULL,
10943 &pending_exception);
10944 }
10945 }
10946 if (!pending_exception) {
10947 return *result;
10948 } else {
10949 return Failure::Exception();
10950 }
10951}
10952
10953
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010954// Sets a v8 flag.
10955static MaybeObject* Runtime_SetFlags(Arguments args) {
10956 CONVERT_CHECKED(String, arg, args[0]);
10957 SmartPointer<char> flags =
10958 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10959 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10960 return Heap::undefined_value();
10961}
10962
10963
10964// Performs a GC.
10965// Presently, it only does a full GC.
10966static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10967 Heap::CollectAllGarbage(true);
10968 return Heap::undefined_value();
10969}
10970
10971
10972// Gets the current heap usage.
10973static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10974 int usage = static_cast<int>(Heap::SizeOfObjects());
10975 if (!Smi::IsValid(usage)) {
10976 return *Factory::NewNumberFromInt(usage);
10977 }
10978 return Smi::FromInt(usage);
10979}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010980
10981
10982// Captures a live object list from the present heap.
10983static MaybeObject* Runtime_HasLOLEnabled(Arguments args) {
10984#ifdef LIVE_OBJECT_LIST
10985 return Heap::true_value();
10986#else
10987 return Heap::false_value();
10988#endif
10989}
10990
10991
10992// Captures a live object list from the present heap.
10993static MaybeObject* Runtime_CaptureLOL(Arguments args) {
10994#ifdef LIVE_OBJECT_LIST
10995 return LiveObjectList::Capture();
10996#else
10997 return Heap::undefined_value();
10998#endif
10999}
11000
11001
11002// Deletes the specified live object list.
11003static MaybeObject* Runtime_DeleteLOL(Arguments args) {
11004#ifdef LIVE_OBJECT_LIST
11005 CONVERT_SMI_CHECKED(id, args[0]);
11006 bool success = LiveObjectList::Delete(id);
11007 return success ? Heap::true_value() : Heap::false_value();
11008#else
11009 return Heap::undefined_value();
11010#endif
11011}
11012
11013
11014// Generates the response to a debugger request for a dump of the objects
11015// contained in the difference between the captured live object lists
11016// specified by id1 and id2.
11017// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11018// dumped.
11019static MaybeObject* Runtime_DumpLOL(Arguments args) {
11020#ifdef LIVE_OBJECT_LIST
11021 HandleScope scope;
11022 CONVERT_SMI_CHECKED(id1, args[0]);
11023 CONVERT_SMI_CHECKED(id2, args[1]);
11024 CONVERT_SMI_CHECKED(start, args[2]);
11025 CONVERT_SMI_CHECKED(count, args[3]);
11026 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11027 EnterDebugger enter_debugger;
11028 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11029#else
11030 return Heap::undefined_value();
11031#endif
11032}
11033
11034
11035// Gets the specified object as requested by the debugger.
11036// This is only used for obj ids shown in live object lists.
11037static MaybeObject* Runtime_GetLOLObj(Arguments args) {
11038#ifdef LIVE_OBJECT_LIST
11039 CONVERT_SMI_CHECKED(obj_id, args[0]);
11040 Object* result = LiveObjectList::GetObj(obj_id);
11041 return result;
11042#else
11043 return Heap::undefined_value();
11044#endif
11045}
11046
11047
11048// Gets the obj id for the specified address if valid.
11049// This is only used for obj ids shown in live object lists.
11050static MaybeObject* Runtime_GetLOLObjId(Arguments args) {
11051#ifdef LIVE_OBJECT_LIST
11052 HandleScope scope;
11053 CONVERT_ARG_CHECKED(String, address, 0);
11054 Object* result = LiveObjectList::GetObjId(address);
11055 return result;
11056#else
11057 return Heap::undefined_value();
11058#endif
11059}
11060
11061
11062// Gets the retainers that references the specified object alive.
11063static MaybeObject* Runtime_GetLOLObjRetainers(Arguments args) {
11064#ifdef LIVE_OBJECT_LIST
11065 HandleScope scope;
11066 CONVERT_SMI_CHECKED(obj_id, args[0]);
11067 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11068 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11069 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11070 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11071 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11072
11073 Handle<JSObject> instance_filter;
11074 if (args[1]->IsJSObject()) {
11075 instance_filter = args.at<JSObject>(1);
11076 }
11077 bool verbose = false;
11078 if (args[2]->IsBoolean()) {
11079 verbose = args[2]->IsTrue();
11080 }
11081 int start = 0;
11082 if (args[3]->IsSmi()) {
11083 start = Smi::cast(args[3])->value();
11084 }
11085 int limit = Smi::kMaxValue;
11086 if (args[4]->IsSmi()) {
11087 limit = Smi::cast(args[4])->value();
11088 }
11089
11090 return LiveObjectList::GetObjRetainers(obj_id,
11091 instance_filter,
11092 verbose,
11093 start,
11094 limit,
11095 filter_obj);
11096#else
11097 return Heap::undefined_value();
11098#endif
11099}
11100
11101
11102// Gets the reference path between 2 objects.
11103static MaybeObject* Runtime_GetLOLPath(Arguments args) {
11104#ifdef LIVE_OBJECT_LIST
11105 HandleScope scope;
11106 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11107 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11108 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11109
11110 Handle<JSObject> instance_filter;
11111 if (args[2]->IsJSObject()) {
11112 instance_filter = args.at<JSObject>(2);
11113 }
11114
11115 Object* result =
11116 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11117 return result;
11118#else
11119 return Heap::undefined_value();
11120#endif
11121}
11122
11123
11124// Generates the response to a debugger request for a list of all
11125// previously captured live object lists.
11126static MaybeObject* Runtime_InfoLOL(Arguments args) {
11127#ifdef LIVE_OBJECT_LIST
11128 CONVERT_SMI_CHECKED(start, args[0]);
11129 CONVERT_SMI_CHECKED(count, args[1]);
11130 return LiveObjectList::Info(start, count);
11131#else
11132 return Heap::undefined_value();
11133#endif
11134}
11135
11136
11137// Gets a dump of the specified object as requested by the debugger.
11138// This is only used for obj ids shown in live object lists.
11139static MaybeObject* Runtime_PrintLOLObj(Arguments args) {
11140#ifdef LIVE_OBJECT_LIST
11141 HandleScope scope;
11142 CONVERT_SMI_CHECKED(obj_id, args[0]);
11143 Object* result = LiveObjectList::PrintObj(obj_id);
11144 return result;
11145#else
11146 return Heap::undefined_value();
11147#endif
11148}
11149
11150
11151// Resets and releases all previously captured live object lists.
11152static MaybeObject* Runtime_ResetLOL(Arguments args) {
11153#ifdef LIVE_OBJECT_LIST
11154 LiveObjectList::Reset();
11155 return Heap::undefined_value();
11156#else
11157 return Heap::undefined_value();
11158#endif
11159}
11160
11161
11162// Generates the response to a debugger request for a summary of the types
11163// of objects in the difference between the captured live object lists
11164// specified by id1 and id2.
11165// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11166// summarized.
11167static MaybeObject* Runtime_SummarizeLOL(Arguments args) {
11168#ifdef LIVE_OBJECT_LIST
11169 HandleScope scope;
11170 CONVERT_SMI_CHECKED(id1, args[0]);
11171 CONVERT_SMI_CHECKED(id2, args[1]);
11172 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11173
11174 EnterDebugger enter_debugger;
11175 return LiveObjectList::Summarize(id1, id2, filter_obj);
11176#else
11177 return Heap::undefined_value();
11178#endif
11179}
11180
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011181#endif // ENABLE_DEBUGGER_SUPPORT
11182
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011183
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011184#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000011185static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011186 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011187 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011188
11189 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011190 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11191 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011192 return Heap::undefined_value();
11193}
11194
11195
lrn@chromium.org303ada72010-10-27 09:33:13 +000011196static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011197 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011198 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011199
11200 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011201 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11202 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011203 return Heap::undefined_value();
11204}
11205
11206#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011207
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011208// Finds the script object from the script data. NOTE: This operation uses
11209// heap traversal to find the function generated for the source position
11210// for the requested break point. For lazily compiled functions several heap
11211// traversals might be required rendering this operation as a rather slow
11212// operation. However for setting break points which is normally done through
11213// some kind of user interaction the performance is not crucial.
11214static Handle<Object> Runtime_GetScriptFromScriptName(
11215 Handle<String> script_name) {
11216 // Scan the heap for Script objects to find the script with the requested
11217 // script data.
11218 Handle<Script> script;
11219 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011220 HeapObject* obj = NULL;
11221 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011222 // If a script is found check if it has the script data requested.
11223 if (obj->IsScript()) {
11224 if (Script::cast(obj)->name()->IsString()) {
11225 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11226 script = Handle<Script>(Script::cast(obj));
11227 }
11228 }
11229 }
11230 }
11231
11232 // If no script with the requested script data is found return undefined.
11233 if (script.is_null()) return Factory::undefined_value();
11234
11235 // Return the script found.
11236 return GetScriptWrapper(script);
11237}
11238
11239
11240// Get the script object from script data. NOTE: Regarding performance
11241// see the NOTE for GetScriptFromScriptData.
11242// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000011243static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011244 HandleScope scope;
11245
11246 ASSERT(args.length() == 1);
11247
11248 CONVERT_CHECKED(String, script_name, args[0]);
11249
11250 // Find the requested script.
11251 Handle<Object> result =
11252 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11253 return *result;
11254}
11255
11256
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011257// Determines whether the given stack frame should be displayed in
11258// a stack trace. The caller is the error constructor that asked
11259// for the stack trace to be collected. The first time a construct
11260// call to this function is encountered it is skipped. The seen_caller
11261// in/out parameter is used to remember if the caller has been seen
11262// yet.
11263static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11264 bool* seen_caller) {
11265 // Only display JS frames.
11266 if (!raw_frame->is_java_script())
11267 return false;
11268 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11269 Object* raw_fun = frame->function();
11270 // Not sure when this can happen but skip it just in case.
11271 if (!raw_fun->IsJSFunction())
11272 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011273 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011274 *seen_caller = true;
11275 return false;
11276 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011277 // Skip all frames until we've seen the caller. Also, skip the most
11278 // obvious builtin calls. Some builtin calls (such as Number.ADD
11279 // which is invoked using 'call') are very difficult to recognize
11280 // so we're leaving them in for now.
11281 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011282}
11283
11284
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011285// Collect the raw data for a stack trace. Returns an array of 4
11286// element segments each containing a receiver, function, code and
11287// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011288static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011289 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011290 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011291 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11292
11293 HandleScope scope;
11294
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011295 limit = Max(limit, 0); // Ensure that limit is not negative.
11296 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011297 Handle<FixedArray> elements =
11298 Factory::NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011299
11300 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011301 // If the caller parameter is a function we skip frames until we're
11302 // under it before starting to collect.
11303 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011304 int cursor = 0;
11305 int frames_seen = 0;
11306 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011307 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011308 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011309 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011310 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011311 List<FrameSummary> frames(3); // Max 2 levels of inlining.
11312 frame->Summarize(&frames);
11313 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011314 if (cursor + 4 > elements->length()) {
11315 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11316 Handle<FixedArray> new_elements =
11317 Factory::NewFixedArrayWithHoles(new_capacity);
11318 for (int i = 0; i < cursor; i++) {
11319 new_elements->set(i, elements->get(i));
11320 }
11321 elements = new_elements;
11322 }
11323 ASSERT(cursor + 4 <= elements->length());
11324
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011325 Handle<Object> recv = frames[i].receiver();
11326 Handle<JSFunction> fun = frames[i].function();
11327 Handle<Code> code = frames[i].code();
11328 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011329 elements->set(cursor++, *recv);
11330 elements->set(cursor++, *fun);
11331 elements->set(cursor++, *code);
11332 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011333 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011334 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011335 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011336 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011337 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011338 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011339 return *result;
11340}
11341
11342
ager@chromium.org3811b432009-10-28 14:53:37 +000011343// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011344static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011345 ASSERT_EQ(args.length(), 0);
11346
11347 NoHandleAllocation ha;
11348
11349 const char* version_string = v8::V8::GetVersion();
11350
11351 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
11352}
11353
11354
lrn@chromium.org303ada72010-10-27 09:33:13 +000011355static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011356 ASSERT(args.length() == 2);
11357 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11358 Smi::cast(args[1])->value());
11359 Top::PrintStack();
11360 OS::Abort();
11361 UNREACHABLE();
11362 return NULL;
11363}
11364
11365
lrn@chromium.org303ada72010-10-27 09:33:13 +000011366static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011367 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011368 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011369 Object* key = args[1];
11370
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011371 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011372 Object* o = cache->get(finger_index);
11373 if (o == key) {
11374 // The fastest case: hit the same place again.
11375 return cache->get(finger_index + 1);
11376 }
11377
11378 for (int i = finger_index - 2;
11379 i >= JSFunctionResultCache::kEntriesIndex;
11380 i -= 2) {
11381 o = cache->get(i);
11382 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011383 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011384 return cache->get(i + 1);
11385 }
11386 }
11387
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011388 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011389 ASSERT(size <= cache->length());
11390
11391 for (int i = size - 2; i > finger_index; i -= 2) {
11392 o = cache->get(i);
11393 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011394 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011395 return cache->get(i + 1);
11396 }
11397 }
11398
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011399 // There is no value in the cache. Invoke the function and cache result.
11400 HandleScope scope;
11401
11402 Handle<JSFunctionResultCache> cache_handle(cache);
11403 Handle<Object> key_handle(key);
11404 Handle<Object> value;
11405 {
11406 Handle<JSFunction> factory(JSFunction::cast(
11407 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11408 // TODO(antonm): consider passing a receiver when constructing a cache.
11409 Handle<Object> receiver(Top::global_context()->global());
11410 // This handle is nor shared, nor used later, so it's safe.
11411 Object** argv[] = { key_handle.location() };
11412 bool pending_exception = false;
11413 value = Execution::Call(factory,
11414 receiver,
11415 1,
11416 argv,
11417 &pending_exception);
11418 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011419 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011420
11421#ifdef DEBUG
11422 cache_handle->JSFunctionResultCacheVerify();
11423#endif
11424
11425 // Function invocation may have cleared the cache. Reread all the data.
11426 finger_index = cache_handle->finger_index();
11427 size = cache_handle->size();
11428
11429 // If we have spare room, put new data into it, otherwise evict post finger
11430 // entry which is likely to be the least recently used.
11431 int index = -1;
11432 if (size < cache_handle->length()) {
11433 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11434 index = size;
11435 } else {
11436 index = finger_index + JSFunctionResultCache::kEntrySize;
11437 if (index == cache_handle->length()) {
11438 index = JSFunctionResultCache::kEntriesIndex;
11439 }
11440 }
11441
11442 ASSERT(index % 2 == 0);
11443 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11444 ASSERT(index < cache_handle->length());
11445
11446 cache_handle->set(index, *key_handle);
11447 cache_handle->set(index + 1, *value);
11448 cache_handle->set_finger_index(index);
11449
11450#ifdef DEBUG
11451 cache_handle->JSFunctionResultCacheVerify();
11452#endif
11453
11454 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011455}
11456
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011457
11458static MaybeObject* Runtime_NewMessageObject(Arguments args) {
11459 HandleScope scope;
11460 CONVERT_ARG_CHECKED(String, type, 0);
11461 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
11462 return *Factory::NewJSMessageObject(type,
11463 arguments,
11464 0,
11465 0,
11466 Factory::undefined_value(),
11467 Factory::undefined_value(),
11468 Factory::undefined_value());
11469}
11470
11471
11472static MaybeObject* Runtime_MessageGetType(Arguments args) {
11473 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11474 return message->type();
11475}
11476
11477
11478static MaybeObject* Runtime_MessageGetArguments(Arguments args) {
11479 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11480 return message->arguments();
11481}
11482
11483
11484static MaybeObject* Runtime_MessageGetStartPosition(Arguments args) {
11485 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11486 return Smi::FromInt(message->start_position());
11487}
11488
11489
11490static MaybeObject* Runtime_MessageGetScript(Arguments args) {
11491 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11492 return message->script();
11493}
11494
11495
kasper.lund44510672008-07-25 07:37:58 +000011496#ifdef DEBUG
11497// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11498// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011499static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000011500 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011501 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011502#define COUNT_ENTRY(Name, argc, ressize) + 1
11503 int entry_count = 0
11504 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
11505 INLINE_FUNCTION_LIST(COUNT_ENTRY)
11506 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
11507#undef COUNT_ENTRY
11508 Handle<FixedArray> elements = Factory::NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011509 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011510 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011511#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011512 { \
11513 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011514 Handle<String> name; \
11515 /* Inline runtime functions have an underscore in front of the name. */ \
11516 if (inline_runtime_functions) { \
11517 name = Factory::NewStringFromAscii( \
11518 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11519 } else { \
11520 name = Factory::NewStringFromAscii( \
11521 Vector<const char>(#Name, StrLength(#Name))); \
11522 } \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011523 Handle<FixedArray> pair_elements = Factory::NewFixedArray(2); \
11524 pair_elements->set(0, *name); \
11525 pair_elements->set(1, Smi::FromInt(argc)); \
11526 Handle<JSArray> pair = Factory::NewJSArrayWithElements(pair_elements); \
11527 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011528 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011529 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011530 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011531 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011532 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011533 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011534#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011535 ASSERT_EQ(index, entry_count);
11536 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011537 return *result;
11538}
kasper.lund44510672008-07-25 07:37:58 +000011539#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011540
11541
lrn@chromium.org303ada72010-10-27 09:33:13 +000011542static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011543 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011544 CONVERT_CHECKED(String, format, args[0]);
11545 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011546 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011547 Logger::LogRuntime(chars, elms);
11548 return Heap::undefined_value();
11549}
11550
11551
lrn@chromium.org303ada72010-10-27 09:33:13 +000011552static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011553 UNREACHABLE(); // implemented as macro in the parser
11554 return NULL;
11555}
11556
11557
11558// ----------------------------------------------------------------------------
11559// Implementation of Runtime
11560
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011561#define F(name, number_of_args, result_size) \
11562 { Runtime::k##name, Runtime::RUNTIME, #name, \
11563 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011564
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011565
11566#define I(name, number_of_args, result_size) \
11567 { Runtime::kInline##name, Runtime::INLINE, \
11568 "_" #name, NULL, number_of_args, result_size },
11569
11570Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011571 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011572 INLINE_FUNCTION_LIST(I)
11573 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011574};
11575
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011576
lrn@chromium.org303ada72010-10-27 09:33:13 +000011577MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011578 ASSERT(dictionary != NULL);
11579 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11580 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011581 Object* name_symbol;
11582 { MaybeObject* maybe_name_symbol =
11583 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
11584 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11585 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011586 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011587 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11588 String::cast(name_symbol),
11589 Smi::FromInt(i),
11590 PropertyDetails(NONE, NORMAL));
11591 if (!maybe_dictionary->ToObject(&dictionary)) {
11592 // Non-recoverable failure. Calling code must restart heap
11593 // initialization.
11594 return maybe_dictionary;
11595 }
11596 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011597 }
11598 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011599}
11600
11601
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011602Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11603 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
11604 if (entry != kNotFound) {
11605 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
11606 int function_index = Smi::cast(smi_index)->value();
11607 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011608 }
11609 return NULL;
11610}
11611
11612
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011613Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
11614 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11615}
11616
11617
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011618void Runtime::PerformGC(Object* result) {
11619 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011620 if (failure->IsRetryAfterGC()) {
11621 // Try to do a garbage collection; ignore it if it fails. The C
11622 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000011623 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011624 } else {
11625 // Handle last resort GC and make sure to allow future allocations
11626 // to grow the heap without causing GCs (if possible).
11627 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000011628 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011629 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011630}
11631
11632
11633} } // namespace v8::internal