blob: 88f1bc69fd85df4719cf8fa63f7578dd5d0f440d [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000049#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000050#include "runtime.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"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000053#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000054#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000055#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000056#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
kasperl@chromium.org71affb52009-05-26 05:44:31 +000058namespace v8 {
59namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
61
ager@chromium.org3e875802009-06-29 08:26:34 +000062#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000063 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65// Cast the given object to a value of the specified type and store
66// it in a variable with the given name. If the object is not of the
67// expected type call IllegalOperation and return.
68#define CONVERT_CHECKED(Type, name, obj) \
69 RUNTIME_ASSERT(obj->Is##Type()); \
70 Type* name = Type::cast(obj);
71
72#define CONVERT_ARG_CHECKED(Type, name, index) \
73 RUNTIME_ASSERT(args[index]->Is##Type()); \
74 Handle<Type> name = args.at<Type>(index);
75
kasper.lundbd3ec4e2008-07-09 11:06:54 +000076// Cast the given object to a boolean and store it in a variable with
77// the given name. If the object is not a boolean call IllegalOperation
78// and return.
79#define CONVERT_BOOLEAN_CHECKED(name, obj) \
80 RUNTIME_ASSERT(obj->IsBoolean()); \
81 bool name = (obj)->IsTrue();
82
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000083// Cast the given object to a Smi and store its value in an int variable
84// with the given name. If the object is not a Smi call IllegalOperation
85// and return.
86#define CONVERT_SMI_CHECKED(name, obj) \
87 RUNTIME_ASSERT(obj->IsSmi()); \
88 int name = Smi::cast(obj)->value();
89
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090// Cast the given object to a double and store it in a variable with
91// the given name. If the object is not a number (as opposed to
92// the number not-a-number) call IllegalOperation and return.
93#define CONVERT_DOUBLE_CHECKED(name, obj) \
94 RUNTIME_ASSERT(obj->IsNumber()); \
95 double name = (obj)->Number();
96
97// Call the specified converter on the object *comand store the result in
98// a variable of the specified type with the given name. If the
99// object is not a Number call IllegalOperation and return.
100#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
101 RUNTIME_ASSERT(obj->IsNumber()); \
102 type name = NumberTo##Type(obj);
103
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
106 JSObject* boilerplate) {
107 StackLimitCheck check(isolate);
108 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000110 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000111 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000113 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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000125 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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 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 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000161 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000162 if (!maybe_result->ToObject(&result)) return maybe_result;
163 }
164 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000165 // Creating object copy for literals. No strict mode needed.
166 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 if (!maybe_result->ToObject(&result)) return maybe_result;
168 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000169 }
170 }
171 }
172
173 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000174 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000175 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000176 switch (copy->GetElementsKind()) {
177 case JSObject::FAST_ELEMENTS: {
178 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000179 if (elements->map() == heap->fixed_cow_array_map()) {
180 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000181#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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000191 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
192 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000193 if (!maybe_result->ToObject(&result)) return maybe_result;
194 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000195 elements->set(i, result);
196 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000197 }
198 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000199 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000200 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 case JSObject::DICTIONARY_ELEMENTS: {
202 NumberDictionary* element_dictionary = copy->element_dictionary();
203 int capacity = element_dictionary->Capacity();
204 for (int i = 0; i < capacity; i++) {
205 Object* k = element_dictionary->KeyAt(i);
206 if (element_dictionary->IsKey(k)) {
207 Object* value = element_dictionary->ValueAt(i);
208 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000209 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000210 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
211 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000212 if (!maybe_result->ToObject(&result)) return maybe_result;
213 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000214 element_dictionary->ValueAtPut(i, result);
215 }
216 }
217 }
218 break;
219 }
220 default:
221 UNREACHABLE();
222 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000223 }
224 return copy;
225}
226
227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000228RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000229 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000230 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000231}
232
233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000234RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000236 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000237}
238
239
ager@chromium.org236ad962008-09-25 09:45:57 +0000240static Handle<Map> ComputeObjectLiteralMap(
241 Handle<Context> context,
242 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000243 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000244 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000245 int properties_length = constant_properties->length();
246 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000247 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000248 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000249 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000250 for (int p = 0; p != properties_length; p += 2) {
251 Object* key = constant_properties->get(p);
252 uint32_t element_index = 0;
253 if (key->IsSymbol()) {
254 number_of_symbol_keys++;
255 } else if (key->ToArrayIndex(&element_index)) {
256 // An index key does not require space in the property backing store.
257 number_of_properties--;
258 } else {
259 // Bail out as a non-symbol non-index key makes caching impossible.
260 // ASSERT to make sure that the if condition after the loop is false.
261 ASSERT(number_of_symbol_keys != number_of_properties);
262 break;
263 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 // If we only have symbols and array indices among keys then we can
266 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000268 if ((number_of_symbol_keys == number_of_properties) &&
269 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000270 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000271 Handle<FixedArray> keys =
272 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000273 if (number_of_symbol_keys > 0) {
274 int index = 0;
275 for (int p = 0; p < properties_length; p += 2) {
276 Object* key = constant_properties->get(p);
277 if (key->IsSymbol()) {
278 keys->set(index++, key);
279 }
280 }
281 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000282 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000283 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000284 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000285 }
286 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000287 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000288 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000289 Handle<Map>(context->object_function()->initial_map()),
290 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000291}
292
293
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000294static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000295 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000296 Handle<FixedArray> literals,
297 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000298
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000299
300static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000302 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000303 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 bool should_have_fast_elements,
305 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000306 // Get the global context from the literals array. This is the
307 // context in which the function was created and we use the object
308 // function from this context to create the object literal. We do
309 // not use the object function from the current global context
310 // because this might be the object function from another context
311 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000312 Handle<Context> context =
313 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 // In case we have function literals, we want the object to be in
316 // slow properties mode for now. We don't go in the map cache because
317 // maps with constant functions can't be shared if the functions are
318 // not the same (which is the common case).
319 bool is_result_from_cache = false;
320 Handle<Map> map = has_function_literal
321 ? Handle<Map>(context->object_function()->initial_map())
322 : ComputeObjectLiteralMap(context,
323 constant_properties,
324 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000326 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000327
328 // Normalize the elements of the boilerplate to save space if needed.
329 if (!should_have_fast_elements) NormalizeElements(boilerplate);
330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 // Add the constant properties to the boilerplate.
332 int length = constant_properties->length();
333 bool should_transform =
334 !is_result_from_cache && boilerplate->HasFastProperties();
335 if (should_transform || has_function_literal) {
336 // Normalize the properties of object to avoid n^2 behavior
337 // when extending the object multiple properties. Indicate the number of
338 // properties to be added.
339 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
340 }
341
342 for (int index = 0; index < length; index +=2) {
343 Handle<Object> key(constant_properties->get(index+0), isolate);
344 Handle<Object> value(constant_properties->get(index+1), isolate);
345 if (value->IsFixedArray()) {
346 // The value contains the constant_properties of a
347 // simple object or array literal.
348 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
349 value = CreateLiteralBoilerplate(isolate, literals, array);
350 if (value.is_null()) return value;
351 }
352 Handle<Object> result;
353 uint32_t element_index = 0;
354 if (key->IsSymbol()) {
355 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
356 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000357 result = SetOwnElement(boilerplate,
358 element_index,
359 value,
360 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000362 Handle<String> name(String::cast(*key));
363 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000364 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
365 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000366 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 } else if (key->ToArrayIndex(&element_index)) {
368 // Array index (uint32).
369 result = SetOwnElement(boilerplate,
370 element_index,
371 value,
372 kNonStrictMode);
373 } else {
374 // Non-uint32 number.
375 ASSERT(key->IsNumber());
376 double num = key->Number();
377 char arr[100];
378 Vector<char> buffer(arr, ARRAY_SIZE(arr));
379 const char* str = DoubleToCString(num, buffer);
380 Handle<String> name =
381 isolate->factory()->NewStringFromAscii(CStrVector(str));
382 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
383 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000385 // If setting the property on the boilerplate throws an
386 // exception, the exception is converted to an empty handle in
387 // the handle based operations. In that case, we need to
388 // convert back to an exception.
389 if (result.is_null()) return result;
390 }
391
392 // Transform to fast properties if necessary. For object literals with
393 // containing function literals we defer this operation until after all
394 // computed properties have been assigned so that we can generate
395 // constant function properties.
396 if (should_transform && !has_function_literal) {
397 TransformToFastProperties(boilerplate,
398 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 }
400
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000401 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000402}
403
404
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000405static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000406 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000407 Handle<FixedArray> literals,
408 Handle<FixedArray> elements) {
409 // Create the JSArray.
410 Handle<JSFunction> constructor(
411 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000412 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 const bool is_cow =
415 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000416 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000418
419 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000420 if (is_cow) {
421#ifdef DEBUG
422 // Copy-on-write arrays must be shallow (and simple).
423 for (int i = 0; i < content->length(); i++) {
424 ASSERT(!content->get(i)->IsFixedArray());
425 }
426#endif
427 } else {
428 for (int i = 0; i < content->length(); i++) {
429 if (content->get(i)->IsFixedArray()) {
430 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000432 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
433 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000434 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000435 if (result.is_null()) return result;
436 content->set(i, *result);
437 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438 }
439 }
440
441 // Set the elements.
442 Handle<JSArray>::cast(object)->SetContent(*content);
443 return object;
444}
445
446
447static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000448 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000449 Handle<FixedArray> literals,
450 Handle<FixedArray> array) {
451 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000452 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000453 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000454 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000455 return CreateObjectLiteralBoilerplate(isolate,
456 literals,
457 elements,
458 true,
459 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000460 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000461 return CreateObjectLiteralBoilerplate(isolate,
462 literals,
463 elements,
464 false,
465 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000466 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000467 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 default:
469 UNREACHABLE();
470 return Handle<Object>::null();
471 }
472}
473
474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000475RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000476 // Takes a FixedArray of elements containing the literal elements of
477 // the array literal and produces JSArray with those elements.
478 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000479 // which contains the context from which to get the Array function
480 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000481 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000482 ASSERT(args.length() == 3);
483 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
484 CONVERT_SMI_CHECKED(literals_index, args[1]);
485 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000487 Handle<Object> object =
488 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000489 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000490
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000491 // Update the functions literal and return the boilerplate.
492 literals->set(literals_index, *object);
493 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000494}
495
496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000497RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000498 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000499 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000500 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
501 CONVERT_SMI_CHECKED(literals_index, args[1]);
502 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000503 CONVERT_SMI_CHECKED(flags, args[3]);
504 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
505 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000506
507 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000508 Handle<Object> boilerplate(literals->get(literals_index), isolate);
509 if (*boilerplate == isolate->heap()->undefined_value()) {
510 boilerplate = CreateObjectLiteralBoilerplate(isolate,
511 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000512 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000513 should_have_fast_elements,
514 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000515 if (boilerplate.is_null()) return Failure::Exception();
516 // Update the functions literal and return the boilerplate.
517 literals->set(literals_index, *boilerplate);
518 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000520}
521
522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000523RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000525 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000526 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
527 CONVERT_SMI_CHECKED(literals_index, args[1]);
528 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000529 CONVERT_SMI_CHECKED(flags, args[3]);
530 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
531 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000532
533 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 Handle<Object> boilerplate(literals->get(literals_index), isolate);
535 if (*boilerplate == isolate->heap()->undefined_value()) {
536 boilerplate = CreateObjectLiteralBoilerplate(isolate,
537 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000538 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 should_have_fast_elements,
540 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000541 if (boilerplate.is_null()) return Failure::Exception();
542 // Update the functions literal and return the boilerplate.
543 literals->set(literals_index, *boilerplate);
544 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000546}
547
548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000549RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000550 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000551 ASSERT(args.length() == 3);
552 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
553 CONVERT_SMI_CHECKED(literals_index, args[1]);
554 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
555
556 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000557 Handle<Object> boilerplate(literals->get(literals_index), isolate);
558 if (*boilerplate == isolate->heap()->undefined_value()) {
559 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000560 if (boilerplate.is_null()) return Failure::Exception();
561 // Update the functions literal and return the boilerplate.
562 literals->set(literals_index, *boilerplate);
563 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565}
566
567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000568RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000570 ASSERT(args.length() == 3);
571 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
572 CONVERT_SMI_CHECKED(literals_index, args[1]);
573 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
574
575 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000576 Handle<Object> boilerplate(literals->get(literals_index), isolate);
577 if (*boilerplate == isolate->heap()->undefined_value()) {
578 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579 if (boilerplate.is_null()) return Failure::Exception();
580 // Update the functions literal and return the boilerplate.
581 literals->set(literals_index, *boilerplate);
582 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000583 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000585 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000586 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588}
589
590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000591RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000592 ASSERT(args.length() == 2);
593 CONVERT_CHECKED(String, key, args[0]);
594 Object* value = args[1];
595 // Create a catch context extension object.
596 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 isolate->context()->global_context()->
598 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000599 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000601 if (!maybe_object->ToObject(&object)) return maybe_object;
602 }
ager@chromium.org32912102009-01-16 10:38:43 +0000603 // Assign the exception value to the catch variable and make sure
604 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000605 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000606 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
607 JSObject::cast(object)->SetProperty(
608 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000609 if (!maybe_value->ToObject(&value)) return maybe_value;
610 }
ager@chromium.org32912102009-01-16 10:38:43 +0000611 return object;
612}
613
614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000615RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616 NoHandleAllocation ha;
617 ASSERT(args.length() == 1);
618 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 return JSObject::cast(obj)->class_name();
621}
622
ager@chromium.org7c537e22008-10-16 08:43:32 +0000623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000624RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000625 NoHandleAllocation ha;
626 ASSERT(args.length() == 2);
627 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
628 Object* O = args[0];
629 Object* V = args[1];
630 while (true) {
631 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 if (prototype->IsNull()) return isolate->heap()->false_value();
633 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634 V = prototype;
635 }
636}
637
638
ager@chromium.org9085a012009-05-11 19:22:57 +0000639// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000640RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000641 NoHandleAllocation ha;
642 ASSERT(args.length() == 2);
643 CONVERT_CHECKED(JSObject, jsobject, args[0]);
644 CONVERT_CHECKED(JSObject, proto, args[1]);
645
646 // Sanity checks. The old prototype (that we are replacing) could
647 // theoretically be null, but if it is not null then check that we
648 // didn't already install a hidden prototype here.
649 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
650 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
651 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
652
653 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000654 Object* map_or_failure;
655 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
656 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
657 return maybe_map_or_failure;
658 }
659 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000660 Map* new_proto_map = Map::cast(map_or_failure);
661
lrn@chromium.org303ada72010-10-27 09:33:13 +0000662 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
663 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
664 return maybe_map_or_failure;
665 }
666 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000667 Map* new_map = Map::cast(map_or_failure);
668
669 // Set proto's prototype to be the old prototype of the object.
670 new_proto_map->set_prototype(jsobject->GetPrototype());
671 proto->set_map(new_proto_map);
672 new_proto_map->set_is_hidden_prototype();
673
674 // Set the object's prototype to proto.
675 new_map->set_prototype(proto);
676 jsobject->set_map(new_map);
677
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000678 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000679}
680
681
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000682RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000683 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000684 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000685 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000686 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000687}
688
689
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000690// Recursively traverses hidden prototypes if property is not found
691static void GetOwnPropertyImplementation(JSObject* obj,
692 String* name,
693 LookupResult* result) {
694 obj->LocalLookupRealNamedProperty(name, result);
695
696 if (!result->IsProperty()) {
697 Object* proto = obj->GetPrototype();
698 if (proto->IsJSObject() &&
699 JSObject::cast(proto)->map()->is_hidden_prototype())
700 GetOwnPropertyImplementation(JSObject::cast(proto),
701 name, result);
702 }
703}
704
705
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000706static bool CheckAccessException(LookupResult* result,
707 v8::AccessType access_type) {
708 if (result->type() == CALLBACKS) {
709 Object* callback = result->GetCallbackObject();
710 if (callback->IsAccessorInfo()) {
711 AccessorInfo* info = AccessorInfo::cast(callback);
712 bool can_access =
713 (access_type == v8::ACCESS_HAS &&
714 (info->all_can_read() || info->all_can_write())) ||
715 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
716 (access_type == v8::ACCESS_SET && info->all_can_write());
717 return can_access;
718 }
719 }
720
721 return false;
722}
723
724
725static bool CheckAccess(JSObject* obj,
726 String* name,
727 LookupResult* result,
728 v8::AccessType access_type) {
729 ASSERT(result->IsProperty());
730
731 JSObject* holder = result->holder();
732 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000733 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000734 while (true) {
735 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000736 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000737 // Access check callback denied the access, but some properties
738 // can have a special permissions which override callbacks descision
739 // (currently see v8::AccessControl).
740 break;
741 }
742
743 if (current == holder) {
744 return true;
745 }
746
747 current = JSObject::cast(current->GetPrototype());
748 }
749
750 // API callbacks can have per callback access exceptions.
751 switch (result->type()) {
752 case CALLBACKS: {
753 if (CheckAccessException(result, access_type)) {
754 return true;
755 }
756 break;
757 }
758 case INTERCEPTOR: {
759 // If the object has an interceptor, try real named properties.
760 // Overwrite the result to fetch the correct property later.
761 holder->LookupRealNamedProperty(name, result);
762 if (result->IsProperty()) {
763 if (CheckAccessException(result, access_type)) {
764 return true;
765 }
766 }
767 break;
768 }
769 default:
770 break;
771 }
772
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000773 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000774 return false;
775}
776
777
778// TODO(1095): we should traverse hidden prototype hierachy as well.
779static bool CheckElementAccess(JSObject* obj,
780 uint32_t index,
781 v8::AccessType access_type) {
782 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000783 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000784 return false;
785 }
786
787 return true;
788}
789
790
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000791// Enumerator used as indices into the array returned from GetOwnProperty
792enum PropertyDescriptorIndices {
793 IS_ACCESSOR_INDEX,
794 VALUE_INDEX,
795 GETTER_INDEX,
796 SETTER_INDEX,
797 WRITABLE_INDEX,
798 ENUMERABLE_INDEX,
799 CONFIGURABLE_INDEX,
800 DESCRIPTOR_SIZE
801};
802
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000803// Returns an array with the property description:
804// if args[1] is not a property on args[0]
805// returns undefined
806// if args[1] is a data property on args[0]
807// [false, value, Writeable, Enumerable, Configurable]
808// if args[1] is an accessor on args[0]
809// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000810RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000811 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000812 Heap* heap = isolate->heap();
813 HandleScope scope(isolate);
814 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
815 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000816 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000817 CONVERT_ARG_CHECKED(JSObject, obj, 0);
818 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000819
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000820 // This could be an element.
821 uint32_t index;
822 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000823 switch (obj->HasLocalElement(index)) {
824 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000825 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000826
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000827 case JSObject::STRING_CHARACTER_ELEMENT: {
828 // Special handling of string objects according to ECMAScript 5
829 // 15.5.5.2. Note that this might be a string object with elements
830 // other than the actual string value. This is covered by the
831 // subsequent cases.
832 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
833 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000834 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000836 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000837 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000838 elms->set(WRITABLE_INDEX, heap->false_value());
839 elms->set(ENUMERABLE_INDEX, heap->false_value());
840 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000841 return *desc;
842 }
843
844 case JSObject::INTERCEPTED_ELEMENT:
845 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000846 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000847 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000848 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000849 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000850 elms->set(WRITABLE_INDEX, heap->true_value());
851 elms->set(ENUMERABLE_INDEX, heap->true_value());
852 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000853 return *desc;
854 }
855
856 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000857 Handle<JSObject> holder = obj;
858 if (obj->IsJSGlobalProxy()) {
859 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000860 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000861 ASSERT(proto->IsJSGlobalObject());
862 holder = Handle<JSObject>(JSObject::cast(proto));
863 }
864 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000865 int entry = dictionary->FindEntry(index);
866 ASSERT(entry != NumberDictionary::kNotFound);
867 PropertyDetails details = dictionary->DetailsAt(entry);
868 switch (details.type()) {
869 case CALLBACKS: {
870 // This is an accessor property with getter and/or setter.
871 FixedArray* callbacks =
872 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000873 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000874 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
875 elms->set(GETTER_INDEX, callbacks->get(0));
876 }
877 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
878 elms->set(SETTER_INDEX, callbacks->get(1));
879 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000880 break;
881 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000882 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000883 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000884 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000885 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000886 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000887 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000888 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000889 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000890 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000891 default:
892 UNREACHABLE();
893 break;
894 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
896 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000897 return *desc;
898 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000899 }
900 }
901
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000902 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000903 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000904
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000905 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000906 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000907 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000908
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000909 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000910 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000911 }
912
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000913 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
914 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000915
916 bool is_js_accessor = (result.type() == CALLBACKS) &&
917 (result.GetCallbackObject()->IsFixedArray());
918
919 if (is_js_accessor) {
920 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000921 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000922
923 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
924 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
925 elms->set(GETTER_INDEX, structure->get(0));
926 }
927 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
928 elms->set(SETTER_INDEX, structure->get(1));
929 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000930 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
932 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000933
934 PropertyAttributes attrs;
935 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000936 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000937 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
938 if (!maybe_value->ToObject(&value)) return maybe_value;
939 }
940 elms->set(VALUE_INDEX, value);
941 }
942
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000943 return *desc;
944}
945
946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000947RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000948 ASSERT(args.length() == 1);
949 CONVERT_CHECKED(JSObject, obj, args[0]);
950 return obj->PreventExtensions();
951}
952
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000954RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000955 ASSERT(args.length() == 1);
956 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000957 if (obj->IsJSGlobalProxy()) {
958 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000959 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000960 ASSERT(proto->IsJSGlobalObject());
961 obj = JSObject::cast(proto);
962 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000963 return obj->map()->is_extensible() ? isolate->heap()->true_value()
964 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000965}
966
967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000968RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000971 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
972 CONVERT_ARG_CHECKED(String, pattern, 1);
973 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000974 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
975 if (result.is_null()) return Failure::Exception();
976 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000977}
978
979
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000980RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000981 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000982 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000983 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000984 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985}
986
987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000988RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000989 ASSERT(args.length() == 1);
990 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000991 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000992 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000993}
994
995
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000996RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 ASSERT(args.length() == 2);
998 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001000 int index = field->value();
1001 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1002 InstanceType type = templ->map()->instance_type();
1003 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1004 type == OBJECT_TEMPLATE_INFO_TYPE);
1005 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001006 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001007 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1008 } else {
1009 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1010 }
1011 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012}
1013
1014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001015RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001016 ASSERT(args.length() == 1);
1017 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001018 Map* old_map = object->map();
1019 bool needs_access_checks = old_map->is_access_check_needed();
1020 if (needs_access_checks) {
1021 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001022 Object* new_map;
1023 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1024 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1025 }
ager@chromium.org32912102009-01-16 10:38:43 +00001026
1027 Map::cast(new_map)->set_is_access_check_needed(false);
1028 object->set_map(Map::cast(new_map));
1029 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001030 return needs_access_checks ? isolate->heap()->true_value()
1031 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001032}
1033
1034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001035RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001036 ASSERT(args.length() == 1);
1037 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001038 Map* old_map = object->map();
1039 if (!old_map->is_access_check_needed()) {
1040 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001041 Object* new_map;
1042 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1043 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1044 }
ager@chromium.org32912102009-01-16 10:38:43 +00001045
1046 Map::cast(new_map)->set_is_access_check_needed(true);
1047 object->set_map(Map::cast(new_map));
1048 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001049 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001050}
1051
1052
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001053static Failure* ThrowRedeclarationError(Isolate* isolate,
1054 const char* type,
1055 Handle<String> name) {
1056 HandleScope scope(isolate);
1057 Handle<Object> type_handle =
1058 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059 Handle<Object> args[2] = { type_handle, name };
1060 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001061 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1062 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063}
1064
1065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001066RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001067 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001068 HandleScope scope(isolate);
1069 Handle<GlobalObject> global = Handle<GlobalObject>(
1070 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071
ager@chromium.org3811b432009-10-28 14:53:37 +00001072 Handle<Context> context = args.at<Context>(0);
1073 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001074 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 StrictModeFlag strict_mode =
1076 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1077 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078
1079 // Compute the property attributes. According to ECMA-262, section
1080 // 13, page 71, the property must be read-only and
1081 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1082 // property as read-only, so we don't either.
1083 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1084
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085 // Traverse the name/value pairs and set the properties.
1086 int length = pairs->length();
1087 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001088 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001089 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001090 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091
1092 // We have to declare a global const property. To capture we only
1093 // assign to it when evaluating the assignment for "const x =
1094 // <expr>" the initial value is the hole.
1095 bool is_const_property = value->IsTheHole();
1096
1097 if (value->IsUndefined() || is_const_property) {
1098 // Lookup the property in the global object, and don't set the
1099 // value of the variable if the property is already there.
1100 LookupResult lookup;
1101 global->Lookup(*name, &lookup);
1102 if (lookup.IsProperty()) {
1103 // Determine if the property is local by comparing the holder
1104 // against the global object. The information will be used to
1105 // avoid throwing re-declaration errors when declaring
1106 // variables or constants that exist in the prototype chain.
1107 bool is_local = (*global == lookup.holder());
1108 // Get the property attributes and determine if the property is
1109 // read-only.
1110 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1111 bool is_read_only = (attributes & READ_ONLY) != 0;
1112 if (lookup.type() == INTERCEPTOR) {
1113 // If the interceptor says the property is there, we
1114 // just return undefined without overwriting the property.
1115 // Otherwise, we continue to setting the property.
1116 if (attributes != ABSENT) {
1117 // Check if the existing property conflicts with regards to const.
1118 if (is_local && (is_read_only || is_const_property)) {
1119 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001120 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001121 };
1122 // The property already exists without conflicting: Go to
1123 // the next declaration.
1124 continue;
1125 }
1126 // Fall-through and introduce the absent property by using
1127 // SetProperty.
1128 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001129 // For const properties, we treat a callback with this name
1130 // even in the prototype as a conflicting declaration.
1131 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001132 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001133 }
1134 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001135 if (is_local && (is_read_only || is_const_property)) {
1136 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001137 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138 }
1139 // The property already exists without conflicting: Go to
1140 // the next declaration.
1141 continue;
1142 }
1143 }
1144 } else {
1145 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001146 Handle<SharedFunctionInfo> shared =
1147 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001149 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1150 context,
1151 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001152 value = function;
1153 }
1154
1155 LookupResult lookup;
1156 global->LocalLookup(*name, &lookup);
1157
1158 PropertyAttributes attributes = is_const_property
1159 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1160 : base;
1161
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001162 // There's a local property that we need to overwrite because
1163 // we're either declaring a function or there's an interceptor
1164 // that claims the property is absent.
1165 //
1166 // Check for conflicting re-declarations. We cannot have
1167 // conflicting types in case of intercepted properties because
1168 // they are absent.
1169 if (lookup.IsProperty() &&
1170 (lookup.type() != INTERCEPTOR) &&
1171 (lookup.IsReadOnly() || is_const_property)) {
1172 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001173 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001174 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001176 // Safari does not allow the invocation of callback setters for
1177 // function declarations. To mimic this behavior, we do not allow
1178 // the invocation of setters for function values. This makes a
1179 // difference for global functions with the same names as event
1180 // handlers such as "function onload() {}". Firefox does call the
1181 // onload setter in those case and Safari does not. We follow
1182 // Safari for compatibility.
1183 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001184 // Do not change DONT_DELETE to false from true.
1185 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1186 attributes = static_cast<PropertyAttributes>(
1187 attributes | (lookup.GetAttributes() & DONT_DELETE));
1188 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 RETURN_IF_EMPTY_HANDLE(isolate,
1190 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001191 name,
1192 value,
1193 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001194 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001195 RETURN_IF_EMPTY_HANDLE(isolate,
1196 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001197 name,
1198 value,
1199 attributes,
1200 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201 }
1202 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001204 ASSERT(!isolate->has_pending_exception());
1205 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001206}
1207
1208
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001209RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001210 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001211 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212
ager@chromium.org7c537e22008-10-16 08:43:32 +00001213 CONVERT_ARG_CHECKED(Context, context, 0);
1214 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001216 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001217 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001218 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219
1220 // Declarations are always done in the function context.
1221 context = Handle<Context>(context->fcontext());
1222
1223 int index;
1224 PropertyAttributes attributes;
1225 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001226 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001227 context->Lookup(name, flags, &index, &attributes);
1228
1229 if (attributes != ABSENT) {
1230 // The name was declared before; check for conflicting
1231 // re-declarations: This is similar to the code in parser.cc in
1232 // the AstBuildingParser::Declare function.
1233 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1234 // Functions are not read-only.
1235 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1236 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001237 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001238 }
1239
1240 // Initialize it if necessary.
1241 if (*initial_value != NULL) {
1242 if (index >= 0) {
1243 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001244 // the function context or the arguments object.
1245 if (holder->IsContext()) {
1246 ASSERT(holder.is_identical_to(context));
1247 if (((attributes & READ_ONLY) == 0) ||
1248 context->get(index)->IsTheHole()) {
1249 context->set(index, *initial_value);
1250 }
1251 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001252 // The holder is an arguments object.
1253 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001254 Handle<Object> result = SetElement(arguments, index, initial_value,
1255 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001256 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 }
1258 } else {
1259 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001260 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001261 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001262 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001263 SetProperty(context_ext, name, initial_value,
1264 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 }
1266 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001269 // The property is not in the function context. It needs to be
1270 // "declared" in the function context's extension context, or in the
1271 // global context.
1272 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001273 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001274 // The function context's extension context exists - use it.
1275 context_ext = Handle<JSObject>(context->extension());
1276 } else {
1277 // The function context's extension context does not exists - allocate
1278 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001279 context_ext = isolate->factory()->NewJSObject(
1280 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001281 // And store it in the extension slot.
1282 context->set_extension(*context_ext);
1283 }
1284 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285
ager@chromium.org7c537e22008-10-16 08:43:32 +00001286 // Declare the property by setting it to the initial value if provided,
1287 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1288 // constant declarations).
1289 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001290 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001291 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001292 // Declaring a const context slot is a conflicting declaration if
1293 // there is a callback with that name in a prototype. It is
1294 // allowed to introduce const variables in
1295 // JSContextExtensionObjects. They are treated specially in
1296 // SetProperty and no setters are invoked for those since they are
1297 // not real JSObjects.
1298 if (initial_value->IsTheHole() &&
1299 !context_ext->IsJSContextExtensionObject()) {
1300 LookupResult lookup;
1301 context_ext->Lookup(*name, &lookup);
1302 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001303 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001304 }
1305 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001306 RETURN_IF_EMPTY_HANDLE(isolate,
1307 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001308 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001309 }
1310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001311 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312}
1313
1314
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001315RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001317 // args[0] == name
1318 // args[1] == strict_mode
1319 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320
1321 // Determine if we need to assign to the variable if it already
1322 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001323 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1324 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325
1326 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001327 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001328 RUNTIME_ASSERT(args[1]->IsSmi());
1329 StrictModeFlag strict_mode =
1330 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1331 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332
1333 // According to ECMA-262, section 12.2, page 62, the property must
1334 // not be deletable.
1335 PropertyAttributes attributes = DONT_DELETE;
1336
1337 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001338 // there, there is a property with this name in the prototype chain.
1339 // We follow Safari and Firefox behavior and only set the property
1340 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001341 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001342 // Note that objects can have hidden prototypes, so we need to traverse
1343 // the whole chain of hidden prototypes to do a 'local' lookup.
1344 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001346 while (true) {
1347 real_holder->LocalLookup(*name, &lookup);
1348 if (lookup.IsProperty()) {
1349 // Determine if this is a redeclaration of something read-only.
1350 if (lookup.IsReadOnly()) {
1351 // If we found readonly property on one of hidden prototypes,
1352 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001353 if (real_holder != isolate->context()->global()) break;
1354 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001355 }
1356
1357 // Determine if this is a redeclaration of an intercepted read-only
1358 // property and figure out if the property exists at all.
1359 bool found = true;
1360 PropertyType type = lookup.type();
1361 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001362 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001363 Handle<JSObject> holder(real_holder);
1364 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1365 real_holder = *holder;
1366 if (intercepted == ABSENT) {
1367 // The interceptor claims the property isn't there. We need to
1368 // make sure to introduce it.
1369 found = false;
1370 } else if ((intercepted & READ_ONLY) != 0) {
1371 // The property is present, but read-only. Since we're trying to
1372 // overwrite it with a variable declaration we must throw a
1373 // re-declaration error. However if we found readonly property
1374 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001375 if (real_holder != isolate->context()->global()) break;
1376 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001377 }
1378 }
1379
1380 if (found && !assign) {
1381 // The global property is there and we're not assigning any value
1382 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001383 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001384 }
1385
1386 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001387 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001388 return real_holder->SetProperty(
1389 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001390 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001391
1392 Object* proto = real_holder->GetPrototype();
1393 if (!proto->IsJSObject())
1394 break;
1395
1396 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1397 break;
1398
1399 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400 }
1401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001403 if (assign) {
1404 return global->SetProperty(*name, args[2], attributes, strict_mode);
1405 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001406 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407}
1408
1409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001410RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411 // All constants are declared with an initial value. The name
1412 // of the constant is the first argument and the initial value
1413 // is the second.
1414 RUNTIME_ASSERT(args.length() == 2);
1415 CONVERT_ARG_CHECKED(String, name, 0);
1416 Handle<Object> value = args.at<Object>(1);
1417
1418 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001419 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420
1421 // According to ECMA-262, section 12.2, page 62, the property must
1422 // not be deletable. Since it's a const, it must be READ_ONLY too.
1423 PropertyAttributes attributes =
1424 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1425
1426 // Lookup the property locally in the global object. If it isn't
1427 // there, we add the property and take special precautions to always
1428 // add it as a local property even in case of callbacks in the
1429 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001430 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431 LookupResult lookup;
1432 global->LocalLookup(*name, &lookup);
1433 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001434 return global->SetLocalPropertyIgnoreAttributes(*name,
1435 *value,
1436 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001437 }
1438
1439 // Determine if this is a redeclaration of something not
1440 // read-only. In case the result is hidden behind an interceptor we
1441 // need to ask it for the property attributes.
1442 if (!lookup.IsReadOnly()) {
1443 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001444 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445 }
1446
1447 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1448
1449 // Throw re-declaration error if the intercepted property is present
1450 // but not read-only.
1451 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001452 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001453 }
1454
1455 // Restore global object from context (in case of GC) and continue
1456 // with setting the value because the property is either absent or
1457 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458 HandleScope handle_scope(isolate);
1459 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001461 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001462 // property through an interceptor and only do it if it's
1463 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001464 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001465 RETURN_IF_EMPTY_HANDLE(isolate,
1466 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001467 name,
1468 value,
1469 attributes,
1470 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 return *value;
1472 }
1473
1474 // Set the value, but only we're assigning the initial value to a
1475 // constant. For now, we determine this by checking if the
1476 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001477 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001478 PropertyType type = lookup.type();
1479 if (type == FIELD) {
1480 FixedArray* properties = global->properties();
1481 int index = lookup.GetFieldIndex();
1482 if (properties->get(index)->IsTheHole()) {
1483 properties->set(index, *value);
1484 }
1485 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001486 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1487 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001488 }
1489 } else {
1490 // Ignore re-initialization of constants that have already been
1491 // assigned a function value.
1492 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1493 }
1494
1495 // Use the set value as the result of the operation.
1496 return *value;
1497}
1498
1499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001500RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001501 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 ASSERT(args.length() == 3);
1503
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001504 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001505 ASSERT(!value->IsTheHole());
1506 CONVERT_ARG_CHECKED(Context, context, 1);
1507 Handle<String> name(String::cast(args[2]));
1508
1509 // Initializations are always done in the function context.
1510 context = Handle<Context>(context->fcontext());
1511
1512 int index;
1513 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001514 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001515 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001516 context->Lookup(name, flags, &index, &attributes);
1517
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001518 // In most situations, the property introduced by the const
1519 // declaration should be present in the context extension object.
1520 // However, because declaration and initialization are separate, the
1521 // property might have been deleted (if it was introduced by eval)
1522 // before we reach the initialization point.
1523 //
1524 // Example:
1525 //
1526 // function f() { eval("delete x; const x;"); }
1527 //
1528 // In that case, the initialization behaves like a normal assignment
1529 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001530 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001531 // Property was found in a context.
1532 if (holder->IsContext()) {
1533 // The holder cannot be the function context. If it is, there
1534 // should have been a const redeclaration error when declaring
1535 // the const property.
1536 ASSERT(!holder.is_identical_to(context));
1537 if ((attributes & READ_ONLY) == 0) {
1538 Handle<Context>::cast(holder)->set(index, *value);
1539 }
1540 } else {
1541 // The holder is an arguments object.
1542 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001543 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001544 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001545 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001546 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547 }
1548 return *value;
1549 }
1550
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001551 // The property could not be found, we introduce it in the global
1552 // context.
1553 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001554 Handle<JSObject> global = Handle<JSObject>(
1555 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001556 // Strict mode not needed (const disallowed in strict mode).
1557 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001558 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001559 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001560 return *value;
1561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001563 // The property was present in a context extension object.
1564 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001565
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001566 if (*context_ext == context->extension()) {
1567 // This is the property that was introduced by the const
1568 // declaration. Set it if it hasn't been set before. NOTE: We
1569 // cannot use GetProperty() to get the current value as it
1570 // 'unholes' the value.
1571 LookupResult lookup;
1572 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1573 ASSERT(lookup.IsProperty()); // the property was declared
1574 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1575
1576 PropertyType type = lookup.type();
1577 if (type == FIELD) {
1578 FixedArray* properties = context_ext->properties();
1579 int index = lookup.GetFieldIndex();
1580 if (properties->get(index)->IsTheHole()) {
1581 properties->set(index, *value);
1582 }
1583 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001584 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1585 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001586 }
1587 } else {
1588 // We should not reach here. Any real, named property should be
1589 // either a field or a dictionary slot.
1590 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591 }
1592 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001593 // The property was found in a different context extension object.
1594 // Set it if it is not a read-only property.
1595 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001596 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001597 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001598 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001599 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001602
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603 return *value;
1604}
1605
1606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001607RUNTIME_FUNCTION(MaybeObject*,
1608 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001609 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001610 ASSERT(args.length() == 2);
1611 CONVERT_ARG_CHECKED(JSObject, object, 0);
1612 CONVERT_SMI_CHECKED(properties, args[1]);
1613 if (object->HasFastProperties()) {
1614 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1615 }
1616 return *object;
1617}
1618
1619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001620RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001621 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001622 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001623 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1624 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001625 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001626 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001627 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001628 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001629 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001630 RUNTIME_ASSERT(index >= 0);
1631 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001632 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001633 Handle<Object> result = RegExpImpl::Exec(regexp,
1634 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001635 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001636 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001637 if (result.is_null()) return Failure::Exception();
1638 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001639}
1640
1641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001642RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001643 ASSERT(args.length() == 3);
1644 CONVERT_SMI_CHECKED(elements_count, args[0]);
1645 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001646 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001647 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001648 Object* new_object;
1649 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001650 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001651 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1652 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001653 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001654 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1655 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001656 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1657 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001658 {
1659 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001660 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001661 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001662 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001663 }
1664 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001665 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001666 array->set_elements(elements);
1667 array->set_length(Smi::FromInt(elements_count));
1668 // Write in-object properties after the length of the array.
1669 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1670 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1671 return array;
1672}
1673
1674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001675RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001676 AssertNoAllocation no_alloc;
1677 ASSERT(args.length() == 5);
1678 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1679 CONVERT_CHECKED(String, source, args[1]);
1680
1681 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001682 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001683
1684 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001685 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001686
1687 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001689
1690 Map* map = regexp->map();
1691 Object* constructor = map->constructor();
1692 if (constructor->IsJSFunction() &&
1693 JSFunction::cast(constructor)->initial_map() == map) {
1694 // If we still have the original map, set in-object properties directly.
1695 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1696 // TODO(lrn): Consider skipping write barrier on booleans as well.
1697 // Both true and false should be in oldspace at all times.
1698 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1699 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1700 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1701 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1702 Smi::FromInt(0),
1703 SKIP_WRITE_BARRIER);
1704 return regexp;
1705 }
1706
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001707 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001708 PropertyAttributes final =
1709 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1710 PropertyAttributes writable =
1711 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001712 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001713 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001714 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001715 source,
1716 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001717 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001718 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001719 global,
1720 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001721 ASSERT(!result->IsFailure());
1722 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001723 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001724 ignoreCase,
1725 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001726 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001727 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001728 multiline,
1729 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001730 ASSERT(!result->IsFailure());
1731 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001732 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001733 Smi::FromInt(0),
1734 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001735 ASSERT(!result->IsFailure());
1736 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001737 return regexp;
1738}
1739
1740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001741RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001742 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001743 ASSERT(args.length() == 1);
1744 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1745 // This is necessary to enable fast checks for absence of elements
1746 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001748 return Smi::FromInt(0);
1749}
1750
1751
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001752static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1753 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001754 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001755 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1757 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1758 Handle<JSFunction> optimized =
1759 isolate->factory()->NewFunction(key,
1760 JS_OBJECT_TYPE,
1761 JSObject::kHeaderSize,
1762 code,
1763 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001764 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001765 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001766 return optimized;
1767}
1768
1769
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001770RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001771 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001772 ASSERT(args.length() == 1);
1773 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1774
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001775 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1776 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1777 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1778 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1779 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1780 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1781 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001782
1783 return *holder;
1784}
1785
1786
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001787RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001788 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 Context* global_context =
1790 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001791 return global_context->global()->global_receiver();
1792}
1793
1794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001795RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001796 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797 ASSERT(args.length() == 4);
1798 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1799 int index = Smi::cast(args[1])->value();
1800 Handle<String> pattern = args.at<String>(2);
1801 Handle<String> flags = args.at<String>(3);
1802
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001803 // Get the RegExp function from the context in the literals array.
1804 // This is the RegExp function from the context in which the
1805 // function was created. We do not use the RegExp function from the
1806 // current global context because this might be the RegExp function
1807 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001808 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001809 Handle<JSFunction>(
1810 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001811 // Compute the regular expression literal.
1812 bool has_pending_exception;
1813 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001814 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1815 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001818 return Failure::Exception();
1819 }
1820 literals->set(index, *regexp);
1821 return *regexp;
1822}
1823
1824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001825RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001826 NoHandleAllocation ha;
1827 ASSERT(args.length() == 1);
1828
1829 CONVERT_CHECKED(JSFunction, f, args[0]);
1830 return f->shared()->name();
1831}
1832
1833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001834RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001835 NoHandleAllocation ha;
1836 ASSERT(args.length() == 2);
1837
1838 CONVERT_CHECKED(JSFunction, f, args[0]);
1839 CONVERT_CHECKED(String, name, args[1]);
1840 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001841 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001842}
1843
1844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001845RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001846 NoHandleAllocation ha;
1847 ASSERT(args.length() == 1);
1848
1849 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001850 Object* obj = f->RemovePrototype();
1851 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001853 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001854}
1855
1856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001857RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001858 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001859 ASSERT(args.length() == 1);
1860
1861 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1863 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001864
1865 return *GetScriptWrapper(Handle<Script>::cast(script));
1866}
1867
1868
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001869RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001870 NoHandleAllocation ha;
1871 ASSERT(args.length() == 1);
1872
1873 CONVERT_CHECKED(JSFunction, f, args[0]);
1874 return f->shared()->GetSourceCode();
1875}
1876
1877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001878RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001879 NoHandleAllocation ha;
1880 ASSERT(args.length() == 1);
1881
1882 CONVERT_CHECKED(JSFunction, fun, args[0]);
1883 int pos = fun->shared()->start_position();
1884 return Smi::FromInt(pos);
1885}
1886
1887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001888RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001889 ASSERT(args.length() == 2);
1890
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001891 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001892 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1893
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001894 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1895
1896 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001897 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001898}
1899
1900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001901RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001902 NoHandleAllocation ha;
1903 ASSERT(args.length() == 2);
1904
1905 CONVERT_CHECKED(JSFunction, fun, args[0]);
1906 CONVERT_CHECKED(String, name, args[1]);
1907 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001908 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001909}
1910
1911
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001912RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001913 NoHandleAllocation ha;
1914 ASSERT(args.length() == 2);
1915
1916 CONVERT_CHECKED(JSFunction, fun, args[0]);
1917 CONVERT_CHECKED(Smi, length, args[1]);
1918 fun->shared()->set_length(length->value());
1919 return length;
1920}
1921
1922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001923RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001924 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 ASSERT(args.length() == 2);
1926
1927 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001928 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001929 Object* obj;
1930 { MaybeObject* maybe_obj =
1931 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1932 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1933 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934 return args[0]; // return TOS
1935}
1936
1937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001938RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001939 NoHandleAllocation ha;
1940 ASSERT(args.length() == 1);
1941
1942 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001943 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1944 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001945}
1946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 1);
1951
1952 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001953 return f->IsBuiltin() ? isolate->heap()->true_value() :
1954 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001955}
1956
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001957
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001958RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001959 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960 ASSERT(args.length() == 2);
1961
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001962 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001963 Handle<Object> code = args.at<Object>(1);
1964
1965 Handle<Context> context(target->context());
1966
1967 if (!code->IsNull()) {
1968 RUNTIME_ASSERT(code->IsJSFunction());
1969 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001970 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001971
1972 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001973 return Failure::Exception();
1974 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001975 // Since we don't store the source for this we should never
1976 // optimize this.
1977 shared->code()->set_optimizable(false);
1978
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001979 // Set the code, scope info, formal parameter count,
1980 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001981 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001982 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001983 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001984 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001985 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001986 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001987 // Set the source code of the target function to undefined.
1988 // SetCode is only used for built-in constructors like String,
1989 // Array, and Object, and some web code
1990 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001991 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001992 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001993 // Clear the optimization hints related to the compiled code as these are no
1994 // longer valid when the code is overwritten.
1995 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001996 context = Handle<Context>(fun->context());
1997
1998 // Make sure we get a fresh copy of the literal vector to avoid
1999 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002000 int number_of_literals = fun->NumberOfLiterals();
2001 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002002 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002003 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002004 // Insert the object, regexp and array functions in the literals
2005 // array prefix. These are the functions that will be used when
2006 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002007 literals->set(JSFunction::kLiteralGlobalContextIndex,
2008 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002010 // It's okay to skip the write barrier here because the literals
2011 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002012 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002013 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014 }
2015
2016 target->set_context(*context);
2017 return *target;
2018}
2019
2020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002021RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002022 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002023 ASSERT(args.length() == 2);
2024 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2025 CONVERT_SMI_CHECKED(num, args[1]);
2026 RUNTIME_ASSERT(num >= 0);
2027 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002028 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002029}
2030
2031
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002032MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2033 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002034 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002035 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002036 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002037 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002038 }
2039 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002040 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002041}
2042
2043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002044RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002045 NoHandleAllocation ha;
2046 ASSERT(args.length() == 2);
2047
2048 CONVERT_CHECKED(String, subject, args[0]);
2049 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002050 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002052 uint32_t i = 0;
2053 if (index->IsSmi()) {
2054 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002055 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002056 i = value;
2057 } else {
2058 ASSERT(index->IsHeapNumber());
2059 double value = HeapNumber::cast(index)->value();
2060 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002061 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002062
2063 // Flatten the string. If someone wants to get a char at an index
2064 // in a cons string, it is likely that more indices will be
2065 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002066 Object* flat;
2067 { MaybeObject* maybe_flat = subject->TryFlatten();
2068 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2069 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002070 subject = String::cast(flat);
2071
2072 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002073 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002074 }
2075
2076 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002077}
2078
2079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002080RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002081 NoHandleAllocation ha;
2082 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002083 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002084}
2085
lrn@chromium.org25156de2010-04-06 13:10:27 +00002086
2087class FixedArrayBuilder {
2088 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002089 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2090 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002091 length_(0) {
2092 // Require a non-zero initial size. Ensures that doubling the size to
2093 // extend the array will work.
2094 ASSERT(initial_capacity > 0);
2095 }
2096
2097 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2098 : array_(backing_store),
2099 length_(0) {
2100 // Require a non-zero initial size. Ensures that doubling the size to
2101 // extend the array will work.
2102 ASSERT(backing_store->length() > 0);
2103 }
2104
2105 bool HasCapacity(int elements) {
2106 int length = array_->length();
2107 int required_length = length_ + elements;
2108 return (length >= required_length);
2109 }
2110
2111 void EnsureCapacity(int elements) {
2112 int length = array_->length();
2113 int required_length = length_ + elements;
2114 if (length < required_length) {
2115 int new_length = length;
2116 do {
2117 new_length *= 2;
2118 } while (new_length < required_length);
2119 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002120 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002121 array_->CopyTo(0, *extended_array, 0, length_);
2122 array_ = extended_array;
2123 }
2124 }
2125
2126 void Add(Object* value) {
2127 ASSERT(length_ < capacity());
2128 array_->set(length_, value);
2129 length_++;
2130 }
2131
2132 void Add(Smi* value) {
2133 ASSERT(length_ < capacity());
2134 array_->set(length_, value);
2135 length_++;
2136 }
2137
2138 Handle<FixedArray> array() {
2139 return array_;
2140 }
2141
2142 int length() {
2143 return length_;
2144 }
2145
2146 int capacity() {
2147 return array_->length();
2148 }
2149
2150 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002151 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002152 result_array->set_length(Smi::FromInt(length_));
2153 return result_array;
2154 }
2155
2156 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2157 target_array->set_elements(*array_);
2158 target_array->set_length(Smi::FromInt(length_));
2159 return target_array;
2160 }
2161
2162 private:
2163 Handle<FixedArray> array_;
2164 int length_;
2165};
2166
2167
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002168// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002169const int kStringBuilderConcatHelperLengthBits = 11;
2170const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002171
2172template <typename schar>
2173static inline void StringBuilderConcatHelper(String*,
2174 schar*,
2175 FixedArray*,
2176 int);
2177
lrn@chromium.org25156de2010-04-06 13:10:27 +00002178typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2179 StringBuilderSubstringLength;
2180typedef BitField<int,
2181 kStringBuilderConcatHelperLengthBits,
2182 kStringBuilderConcatHelperPositionBits>
2183 StringBuilderSubstringPosition;
2184
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002185
2186class ReplacementStringBuilder {
2187 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002188 ReplacementStringBuilder(Heap* heap,
2189 Handle<String> subject,
2190 int estimated_part_count)
2191 : heap_(heap),
2192 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002193 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002194 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002195 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002196 // Require a non-zero initial size. Ensures that doubling the size to
2197 // extend the array will work.
2198 ASSERT(estimated_part_count > 0);
2199 }
2200
lrn@chromium.org25156de2010-04-06 13:10:27 +00002201 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2202 int from,
2203 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002204 ASSERT(from >= 0);
2205 int length = to - from;
2206 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002207 if (StringBuilderSubstringLength::is_valid(length) &&
2208 StringBuilderSubstringPosition::is_valid(from)) {
2209 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2210 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002211 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002212 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002213 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002214 builder->Add(Smi::FromInt(-length));
2215 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002216 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002217 }
2218
2219
2220 void EnsureCapacity(int elements) {
2221 array_builder_.EnsureCapacity(elements);
2222 }
2223
2224
2225 void AddSubjectSlice(int from, int to) {
2226 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002227 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002228 }
2229
2230
2231 void AddString(Handle<String> string) {
2232 int length = string->length();
2233 ASSERT(length > 0);
2234 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002235 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002236 is_ascii_ = false;
2237 }
2238 IncrementCharacterCount(length);
2239 }
2240
2241
2242 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002243 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002244 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002245 }
2246
2247 Handle<String> joined_string;
2248 if (is_ascii_) {
2249 joined_string = NewRawAsciiString(character_count_);
2250 AssertNoAllocation no_alloc;
2251 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2252 char* char_buffer = seq->GetChars();
2253 StringBuilderConcatHelper(*subject_,
2254 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002255 *array_builder_.array(),
2256 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002257 } else {
2258 // Non-ASCII.
2259 joined_string = NewRawTwoByteString(character_count_);
2260 AssertNoAllocation no_alloc;
2261 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2262 uc16* char_buffer = seq->GetChars();
2263 StringBuilderConcatHelper(*subject_,
2264 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002265 *array_builder_.array(),
2266 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002267 }
2268 return joined_string;
2269 }
2270
2271
2272 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002273 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002274 V8::FatalProcessOutOfMemory("String.replace result too large.");
2275 }
2276 character_count_ += by;
2277 }
2278
lrn@chromium.org25156de2010-04-06 13:10:27 +00002279 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002280 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002281 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002282
lrn@chromium.org25156de2010-04-06 13:10:27 +00002283 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002284 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002285 CALL_HEAP_FUNCTION(heap_->isolate(),
2286 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002287 }
2288
2289
2290 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002291 CALL_HEAP_FUNCTION(heap_->isolate(),
2292 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002293 }
2294
2295
2296 void AddElement(Object* element) {
2297 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002298 ASSERT(array_builder_.capacity() > array_builder_.length());
2299 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002300 }
2301
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002302 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002303 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002304 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002305 int character_count_;
2306 bool is_ascii_;
2307};
2308
2309
2310class CompiledReplacement {
2311 public:
2312 CompiledReplacement()
2313 : parts_(1), replacement_substrings_(0) {}
2314
2315 void Compile(Handle<String> replacement,
2316 int capture_count,
2317 int subject_length);
2318
2319 void Apply(ReplacementStringBuilder* builder,
2320 int match_from,
2321 int match_to,
2322 Handle<JSArray> last_match_info);
2323
2324 // Number of distinct parts of the replacement pattern.
2325 int parts() {
2326 return parts_.length();
2327 }
2328 private:
2329 enum PartType {
2330 SUBJECT_PREFIX = 1,
2331 SUBJECT_SUFFIX,
2332 SUBJECT_CAPTURE,
2333 REPLACEMENT_SUBSTRING,
2334 REPLACEMENT_STRING,
2335
2336 NUMBER_OF_PART_TYPES
2337 };
2338
2339 struct ReplacementPart {
2340 static inline ReplacementPart SubjectMatch() {
2341 return ReplacementPart(SUBJECT_CAPTURE, 0);
2342 }
2343 static inline ReplacementPart SubjectCapture(int capture_index) {
2344 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2345 }
2346 static inline ReplacementPart SubjectPrefix() {
2347 return ReplacementPart(SUBJECT_PREFIX, 0);
2348 }
2349 static inline ReplacementPart SubjectSuffix(int subject_length) {
2350 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2351 }
2352 static inline ReplacementPart ReplacementString() {
2353 return ReplacementPart(REPLACEMENT_STRING, 0);
2354 }
2355 static inline ReplacementPart ReplacementSubString(int from, int to) {
2356 ASSERT(from >= 0);
2357 ASSERT(to > from);
2358 return ReplacementPart(-from, to);
2359 }
2360
2361 // If tag <= 0 then it is the negation of a start index of a substring of
2362 // the replacement pattern, otherwise it's a value from PartType.
2363 ReplacementPart(int tag, int data)
2364 : tag(tag), data(data) {
2365 // Must be non-positive or a PartType value.
2366 ASSERT(tag < NUMBER_OF_PART_TYPES);
2367 }
2368 // Either a value of PartType or a non-positive number that is
2369 // the negation of an index into the replacement string.
2370 int tag;
2371 // The data value's interpretation depends on the value of tag:
2372 // tag == SUBJECT_PREFIX ||
2373 // tag == SUBJECT_SUFFIX: data is unused.
2374 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2375 // tag == REPLACEMENT_SUBSTRING ||
2376 // tag == REPLACEMENT_STRING: data is index into array of substrings
2377 // of the replacement string.
2378 // tag <= 0: Temporary representation of the substring of the replacement
2379 // string ranging over -tag .. data.
2380 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2381 // substring objects.
2382 int data;
2383 };
2384
2385 template<typename Char>
2386 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2387 Vector<Char> characters,
2388 int capture_count,
2389 int subject_length) {
2390 int length = characters.length();
2391 int last = 0;
2392 for (int i = 0; i < length; i++) {
2393 Char c = characters[i];
2394 if (c == '$') {
2395 int next_index = i + 1;
2396 if (next_index == length) { // No next character!
2397 break;
2398 }
2399 Char c2 = characters[next_index];
2400 switch (c2) {
2401 case '$':
2402 if (i > last) {
2403 // There is a substring before. Include the first "$".
2404 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2405 last = next_index + 1; // Continue after the second "$".
2406 } else {
2407 // Let the next substring start with the second "$".
2408 last = next_index;
2409 }
2410 i = next_index;
2411 break;
2412 case '`':
2413 if (i > last) {
2414 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2415 }
2416 parts->Add(ReplacementPart::SubjectPrefix());
2417 i = next_index;
2418 last = i + 1;
2419 break;
2420 case '\'':
2421 if (i > last) {
2422 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2423 }
2424 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2425 i = next_index;
2426 last = i + 1;
2427 break;
2428 case '&':
2429 if (i > last) {
2430 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2431 }
2432 parts->Add(ReplacementPart::SubjectMatch());
2433 i = next_index;
2434 last = i + 1;
2435 break;
2436 case '0':
2437 case '1':
2438 case '2':
2439 case '3':
2440 case '4':
2441 case '5':
2442 case '6':
2443 case '7':
2444 case '8':
2445 case '9': {
2446 int capture_ref = c2 - '0';
2447 if (capture_ref > capture_count) {
2448 i = next_index;
2449 continue;
2450 }
2451 int second_digit_index = next_index + 1;
2452 if (second_digit_index < length) {
2453 // Peek ahead to see if we have two digits.
2454 Char c3 = characters[second_digit_index];
2455 if ('0' <= c3 && c3 <= '9') { // Double digits.
2456 int double_digit_ref = capture_ref * 10 + c3 - '0';
2457 if (double_digit_ref <= capture_count) {
2458 next_index = second_digit_index;
2459 capture_ref = double_digit_ref;
2460 }
2461 }
2462 }
2463 if (capture_ref > 0) {
2464 if (i > last) {
2465 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2466 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002467 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2469 last = next_index + 1;
2470 }
2471 i = next_index;
2472 break;
2473 }
2474 default:
2475 i = next_index;
2476 break;
2477 }
2478 }
2479 }
2480 if (length > last) {
2481 if (last == 0) {
2482 parts->Add(ReplacementPart::ReplacementString());
2483 } else {
2484 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2485 }
2486 }
2487 }
2488
2489 ZoneList<ReplacementPart> parts_;
2490 ZoneList<Handle<String> > replacement_substrings_;
2491};
2492
2493
2494void CompiledReplacement::Compile(Handle<String> replacement,
2495 int capture_count,
2496 int subject_length) {
2497 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002498 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002499 AssertNoAllocation no_alloc;
2500 ParseReplacementPattern(&parts_,
2501 replacement->ToAsciiVector(),
2502 capture_count,
2503 subject_length);
2504 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002505 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002506 AssertNoAllocation no_alloc;
2507
2508 ParseReplacementPattern(&parts_,
2509 replacement->ToUC16Vector(),
2510 capture_count,
2511 subject_length);
2512 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002513 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002514 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002515 int substring_index = 0;
2516 for (int i = 0, n = parts_.length(); i < n; i++) {
2517 int tag = parts_[i].tag;
2518 if (tag <= 0) { // A replacement string slice.
2519 int from = -tag;
2520 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002521 replacement_substrings_.Add(
2522 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002523 parts_[i].tag = REPLACEMENT_SUBSTRING;
2524 parts_[i].data = substring_index;
2525 substring_index++;
2526 } else if (tag == REPLACEMENT_STRING) {
2527 replacement_substrings_.Add(replacement);
2528 parts_[i].data = substring_index;
2529 substring_index++;
2530 }
2531 }
2532}
2533
2534
2535void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2536 int match_from,
2537 int match_to,
2538 Handle<JSArray> last_match_info) {
2539 for (int i = 0, n = parts_.length(); i < n; i++) {
2540 ReplacementPart part = parts_[i];
2541 switch (part.tag) {
2542 case SUBJECT_PREFIX:
2543 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2544 break;
2545 case SUBJECT_SUFFIX: {
2546 int subject_length = part.data;
2547 if (match_to < subject_length) {
2548 builder->AddSubjectSlice(match_to, subject_length);
2549 }
2550 break;
2551 }
2552 case SUBJECT_CAPTURE: {
2553 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002554 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002555 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2556 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2557 if (from >= 0 && to > from) {
2558 builder->AddSubjectSlice(from, to);
2559 }
2560 break;
2561 }
2562 case REPLACEMENT_SUBSTRING:
2563 case REPLACEMENT_STRING:
2564 builder->AddString(replacement_substrings_[part.data]);
2565 break;
2566 default:
2567 UNREACHABLE();
2568 }
2569 }
2570}
2571
2572
2573
lrn@chromium.org303ada72010-10-27 09:33:13 +00002574MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002575 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002576 String* subject,
2577 JSRegExp* regexp,
2578 String* replacement,
2579 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002580 ASSERT(subject->IsFlat());
2581 ASSERT(replacement->IsFlat());
2582
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002583 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002584
2585 int length = subject->length();
2586 Handle<String> subject_handle(subject);
2587 Handle<JSRegExp> regexp_handle(regexp);
2588 Handle<String> replacement_handle(replacement);
2589 Handle<JSArray> last_match_info_handle(last_match_info);
2590 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2591 subject_handle,
2592 0,
2593 last_match_info_handle);
2594 if (match.is_null()) {
2595 return Failure::Exception();
2596 }
2597 if (match->IsNull()) {
2598 return *subject_handle;
2599 }
2600
2601 int capture_count = regexp_handle->CaptureCount();
2602
2603 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002604 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002605 CompiledReplacement compiled_replacement;
2606 compiled_replacement.Compile(replacement_handle,
2607 capture_count,
2608 length);
2609
2610 bool is_global = regexp_handle->GetFlags().is_global();
2611
2612 // Guessing the number of parts that the final result string is built
2613 // from. Global regexps can match any number of times, so we guess
2614 // conservatively.
2615 int expected_parts =
2616 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002617 ReplacementStringBuilder builder(isolate->heap(),
2618 subject_handle,
2619 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002620
2621 // Index of end of last match.
2622 int prev = 0;
2623
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002624 // Number of parts added by compiled replacement plus preceeding
2625 // string and possibly suffix after last match. It is possible for
2626 // all components to use two elements when encoded as two smis.
2627 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002628 bool matched = true;
2629 do {
2630 ASSERT(last_match_info_handle->HasFastElements());
2631 // Increase the capacity of the builder before entering local handle-scope,
2632 // so its internal buffer can safely allocate a new handle if it grows.
2633 builder.EnsureCapacity(parts_added_per_loop);
2634
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002635 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002636 int start, end;
2637 {
2638 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002639 FixedArray* match_info_array =
2640 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002641
2642 ASSERT_EQ(capture_count * 2 + 2,
2643 RegExpImpl::GetLastCaptureCount(match_info_array));
2644 start = RegExpImpl::GetCapture(match_info_array, 0);
2645 end = RegExpImpl::GetCapture(match_info_array, 1);
2646 }
2647
2648 if (prev < start) {
2649 builder.AddSubjectSlice(prev, start);
2650 }
2651 compiled_replacement.Apply(&builder,
2652 start,
2653 end,
2654 last_match_info_handle);
2655 prev = end;
2656
2657 // Only continue checking for global regexps.
2658 if (!is_global) break;
2659
2660 // Continue from where the match ended, unless it was an empty match.
2661 int next = end;
2662 if (start == end) {
2663 next = end + 1;
2664 if (next > length) break;
2665 }
2666
2667 match = RegExpImpl::Exec(regexp_handle,
2668 subject_handle,
2669 next,
2670 last_match_info_handle);
2671 if (match.is_null()) {
2672 return Failure::Exception();
2673 }
2674 matched = !match->IsNull();
2675 } while (matched);
2676
2677 if (prev < length) {
2678 builder.AddSubjectSlice(prev, length);
2679 }
2680
2681 return *(builder.ToString());
2682}
2683
2684
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002685template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002686MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002687 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002688 String* subject,
2689 JSRegExp* regexp,
2690 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002691 ASSERT(subject->IsFlat());
2692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002693 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002694
2695 Handle<String> subject_handle(subject);
2696 Handle<JSRegExp> regexp_handle(regexp);
2697 Handle<JSArray> last_match_info_handle(last_match_info);
2698 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2699 subject_handle,
2700 0,
2701 last_match_info_handle);
2702 if (match.is_null()) return Failure::Exception();
2703 if (match->IsNull()) return *subject_handle;
2704
2705 ASSERT(last_match_info_handle->HasFastElements());
2706
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002707 int start, end;
2708 {
2709 AssertNoAllocation match_info_array_is_not_in_a_handle;
2710 FixedArray* match_info_array =
2711 FixedArray::cast(last_match_info_handle->elements());
2712
2713 start = RegExpImpl::GetCapture(match_info_array, 0);
2714 end = RegExpImpl::GetCapture(match_info_array, 1);
2715 }
2716
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002717 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002718 int new_length = length - (end - start);
2719 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002720 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002721 }
2722 Handle<ResultSeqString> answer;
2723 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002724 answer = Handle<ResultSeqString>::cast(
2725 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002726 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002727 answer = Handle<ResultSeqString>::cast(
2728 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002729 }
2730
2731 // If the regexp isn't global, only match once.
2732 if (!regexp_handle->GetFlags().is_global()) {
2733 if (start > 0) {
2734 String::WriteToFlat(*subject_handle,
2735 answer->GetChars(),
2736 0,
2737 start);
2738 }
2739 if (end < length) {
2740 String::WriteToFlat(*subject_handle,
2741 answer->GetChars() + start,
2742 end,
2743 length);
2744 }
2745 return *answer;
2746 }
2747
2748 int prev = 0; // Index of end of last match.
2749 int next = 0; // Start of next search (prev unless last match was empty).
2750 int position = 0;
2751
2752 do {
2753 if (prev < start) {
2754 // Add substring subject[prev;start] to answer string.
2755 String::WriteToFlat(*subject_handle,
2756 answer->GetChars() + position,
2757 prev,
2758 start);
2759 position += start - prev;
2760 }
2761 prev = end;
2762 next = end;
2763 // Continue from where the match ended, unless it was an empty match.
2764 if (start == end) {
2765 next++;
2766 if (next > length) break;
2767 }
2768 match = RegExpImpl::Exec(regexp_handle,
2769 subject_handle,
2770 next,
2771 last_match_info_handle);
2772 if (match.is_null()) return Failure::Exception();
2773 if (match->IsNull()) break;
2774
2775 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002776 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002777 {
2778 AssertNoAllocation match_info_array_is_not_in_a_handle;
2779 FixedArray* match_info_array =
2780 FixedArray::cast(last_match_info_handle->elements());
2781 start = RegExpImpl::GetCapture(match_info_array, 0);
2782 end = RegExpImpl::GetCapture(match_info_array, 1);
2783 }
2784 } while (true);
2785
2786 if (prev < length) {
2787 // Add substring subject[prev;length] to answer string.
2788 String::WriteToFlat(*subject_handle,
2789 answer->GetChars() + position,
2790 prev,
2791 length);
2792 position += length - prev;
2793 }
2794
2795 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002796 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002797 }
2798
2799 // Shorten string and fill
2800 int string_size = ResultSeqString::SizeFor(position);
2801 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2802 int delta = allocated_string_size - string_size;
2803
2804 answer->set_length(position);
2805 if (delta == 0) return *answer;
2806
2807 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002808 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002809
2810 return *answer;
2811}
2812
2813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002814RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002815 ASSERT(args.length() == 4);
2816
2817 CONVERT_CHECKED(String, subject, args[0]);
2818 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002819 Object* flat_subject;
2820 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2821 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2822 return maybe_flat_subject;
2823 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002824 }
2825 subject = String::cast(flat_subject);
2826 }
2827
2828 CONVERT_CHECKED(String, replacement, args[2]);
2829 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002830 Object* flat_replacement;
2831 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2832 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2833 return maybe_flat_replacement;
2834 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002835 }
2836 replacement = String::cast(flat_replacement);
2837 }
2838
2839 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2840 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2841
2842 ASSERT(last_match_info->HasFastElements());
2843
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002844 if (replacement->length() == 0) {
2845 if (subject->HasOnlyAsciiChars()) {
2846 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002847 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002848 } else {
2849 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002850 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002851 }
2852 }
2853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002854 return StringReplaceRegExpWithString(isolate,
2855 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002856 regexp,
2857 replacement,
2858 last_match_info);
2859}
2860
2861
ager@chromium.org7c537e22008-10-16 08:43:32 +00002862// Perform string match of pattern on subject, starting at start index.
2863// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002864// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002865int Runtime::StringMatch(Isolate* isolate,
2866 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002867 Handle<String> pat,
2868 int start_index) {
2869 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002870 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002871
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002872 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002873 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002874
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002875 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002876 if (start_index + pattern_length > subject_length) return -1;
2877
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002878 if (!sub->IsFlat()) FlattenString(sub);
2879 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002880
ager@chromium.org7c537e22008-10-16 08:43:32 +00002881 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002882 // Extract flattened substrings of cons strings before determining asciiness.
2883 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002884 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002885 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002886 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002887
ager@chromium.org7c537e22008-10-16 08:43:32 +00002888 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002889 if (seq_pat->IsAsciiRepresentation()) {
2890 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2891 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002892 return SearchString(isolate,
2893 seq_sub->ToAsciiVector(),
2894 pat_vector,
2895 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002896 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002897 return SearchString(isolate,
2898 seq_sub->ToUC16Vector(),
2899 pat_vector,
2900 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002901 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002902 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2903 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002904 return SearchString(isolate,
2905 seq_sub->ToAsciiVector(),
2906 pat_vector,
2907 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002908 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002909 return SearchString(isolate,
2910 seq_sub->ToUC16Vector(),
2911 pat_vector,
2912 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002913}
2914
2915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002916RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002917 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002918 ASSERT(args.length() == 3);
2919
ager@chromium.org7c537e22008-10-16 08:43:32 +00002920 CONVERT_ARG_CHECKED(String, sub, 0);
2921 CONVERT_ARG_CHECKED(String, pat, 1);
2922
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002923 Object* index = args[2];
2924 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002925 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002926
ager@chromium.org870a0b62008-11-04 11:43:05 +00002927 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002928 int position =
2929 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002930 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002931}
2932
2933
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002934template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002935static int StringMatchBackwards(Vector<const schar> subject,
2936 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002937 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002938 int pattern_length = pattern.length();
2939 ASSERT(pattern_length >= 1);
2940 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002941
2942 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002943 for (int i = 0; i < pattern_length; i++) {
2944 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002945 if (c > String::kMaxAsciiCharCode) {
2946 return -1;
2947 }
2948 }
2949 }
2950
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002951 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002952 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002953 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002954 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002955 while (j < pattern_length) {
2956 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002957 break;
2958 }
2959 j++;
2960 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002961 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002962 return i;
2963 }
2964 }
2965 return -1;
2966}
2967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002968RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002969 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002970 ASSERT(args.length() == 3);
2971
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002972 CONVERT_ARG_CHECKED(String, sub, 0);
2973 CONVERT_ARG_CHECKED(String, pat, 1);
2974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002975 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002976 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002977 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002978
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002979 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002980 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002981
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002982 if (start_index + pat_length > sub_length) {
2983 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002984 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002985
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002986 if (pat_length == 0) {
2987 return Smi::FromInt(start_index);
2988 }
2989
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002990 if (!sub->IsFlat()) FlattenString(sub);
2991 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002992
2993 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2994
2995 int position = -1;
2996
2997 if (pat->IsAsciiRepresentation()) {
2998 Vector<const char> pat_vector = pat->ToAsciiVector();
2999 if (sub->IsAsciiRepresentation()) {
3000 position = StringMatchBackwards(sub->ToAsciiVector(),
3001 pat_vector,
3002 start_index);
3003 } else {
3004 position = StringMatchBackwards(sub->ToUC16Vector(),
3005 pat_vector,
3006 start_index);
3007 }
3008 } else {
3009 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3010 if (sub->IsAsciiRepresentation()) {
3011 position = StringMatchBackwards(sub->ToAsciiVector(),
3012 pat_vector,
3013 start_index);
3014 } else {
3015 position = StringMatchBackwards(sub->ToUC16Vector(),
3016 pat_vector,
3017 start_index);
3018 }
3019 }
3020
3021 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003022}
3023
3024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003025RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003026 NoHandleAllocation ha;
3027 ASSERT(args.length() == 2);
3028
3029 CONVERT_CHECKED(String, str1, args[0]);
3030 CONVERT_CHECKED(String, str2, args[1]);
3031
3032 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003033 int str1_length = str1->length();
3034 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003035
3036 // Decide trivial cases without flattening.
3037 if (str1_length == 0) {
3038 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3039 return Smi::FromInt(-str2_length);
3040 } else {
3041 if (str2_length == 0) return Smi::FromInt(str1_length);
3042 }
3043
3044 int end = str1_length < str2_length ? str1_length : str2_length;
3045
3046 // No need to flatten if we are going to find the answer on the first
3047 // character. At this point we know there is at least one character
3048 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003049 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003050 if (d != 0) return Smi::FromInt(d);
3051
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003052 str1->TryFlatten();
3053 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003055 StringInputBuffer& buf1 =
3056 *isolate->runtime_state()->string_locale_compare_buf1();
3057 StringInputBuffer& buf2 =
3058 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003059
3060 buf1.Reset(str1);
3061 buf2.Reset(str2);
3062
3063 for (int i = 0; i < end; i++) {
3064 uint16_t char1 = buf1.GetNext();
3065 uint16_t char2 = buf2.GetNext();
3066 if (char1 != char2) return Smi::FromInt(char1 - char2);
3067 }
3068
3069 return Smi::FromInt(str1_length - str2_length);
3070}
3071
3072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003073RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003074 NoHandleAllocation ha;
3075 ASSERT(args.length() == 3);
3076
3077 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003078 Object* from = args[1];
3079 Object* to = args[2];
3080 int start, end;
3081 // We have a fast integer-only case here to avoid a conversion to double in
3082 // the common case where from and to are Smis.
3083 if (from->IsSmi() && to->IsSmi()) {
3084 start = Smi::cast(from)->value();
3085 end = Smi::cast(to)->value();
3086 } else {
3087 CONVERT_DOUBLE_CHECKED(from_number, from);
3088 CONVERT_DOUBLE_CHECKED(to_number, to);
3089 start = FastD2I(from_number);
3090 end = FastD2I(to_number);
3091 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003092 RUNTIME_ASSERT(end >= start);
3093 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003094 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003095 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003096 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003097}
3098
3099
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003100RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003101 ASSERT_EQ(3, args.length());
3102
3103 CONVERT_ARG_CHECKED(String, subject, 0);
3104 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3105 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3106 HandleScope handles;
3107
3108 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3109
3110 if (match.is_null()) {
3111 return Failure::Exception();
3112 }
3113 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003114 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003115 }
3116 int length = subject->length();
3117
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003118 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003119 ZoneList<int> offsets(8);
3120 do {
3121 int start;
3122 int end;
3123 {
3124 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003125 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003126 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3127 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3128 }
3129 offsets.Add(start);
3130 offsets.Add(end);
3131 int index = start < end ? end : end + 1;
3132 if (index > length) break;
3133 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3134 if (match.is_null()) {
3135 return Failure::Exception();
3136 }
3137 } while (!match->IsNull());
3138 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003139 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003140 for (int i = 0; i < matches ; i++) {
3141 int from = offsets.at(i * 2);
3142 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003143 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003144 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003145 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003146 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003147 result->set_length(Smi::FromInt(matches));
3148 return *result;
3149}
3150
3151
lrn@chromium.org25156de2010-04-06 13:10:27 +00003152// Two smis before and after the match, for very long strings.
3153const int kMaxBuilderEntriesPerRegExpMatch = 5;
3154
3155
3156static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3157 Handle<JSArray> last_match_info,
3158 int match_start,
3159 int match_end) {
3160 // Fill last_match_info with a single capture.
3161 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3162 AssertNoAllocation no_gc;
3163 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3164 RegExpImpl::SetLastCaptureCount(elements, 2);
3165 RegExpImpl::SetLastInput(elements, *subject);
3166 RegExpImpl::SetLastSubject(elements, *subject);
3167 RegExpImpl::SetCapture(elements, 0, match_start);
3168 RegExpImpl::SetCapture(elements, 1, match_end);
3169}
3170
3171
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003172template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003173static bool SearchStringMultiple(Isolate* isolate,
3174 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003175 Vector<const PatternChar> pattern,
3176 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003177 FixedArrayBuilder* builder,
3178 int* match_pos) {
3179 int pos = *match_pos;
3180 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003181 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003182 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003183 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003184 while (pos <= max_search_start) {
3185 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3186 *match_pos = pos;
3187 return false;
3188 }
3189 // Position of end of previous match.
3190 int match_end = pos + pattern_length;
3191 int new_pos = search.Search(subject, match_end);
3192 if (new_pos >= 0) {
3193 // A match.
3194 if (new_pos > match_end) {
3195 ReplacementStringBuilder::AddSubjectSlice(builder,
3196 match_end,
3197 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003198 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003199 pos = new_pos;
3200 builder->Add(pattern_string);
3201 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003202 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003203 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003204 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003205
lrn@chromium.org25156de2010-04-06 13:10:27 +00003206 if (pos < max_search_start) {
3207 ReplacementStringBuilder::AddSubjectSlice(builder,
3208 pos + pattern_length,
3209 subject_length);
3210 }
3211 *match_pos = pos;
3212 return true;
3213}
3214
3215
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003216static bool SearchStringMultiple(Isolate* isolate,
3217 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003218 Handle<String> pattern,
3219 Handle<JSArray> last_match_info,
3220 FixedArrayBuilder* builder) {
3221 ASSERT(subject->IsFlat());
3222 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003223
3224 // Treating as if a previous match was before first character.
3225 int match_pos = -pattern->length();
3226
3227 for (;;) { // Break when search complete.
3228 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3229 AssertNoAllocation no_gc;
3230 if (subject->IsAsciiRepresentation()) {
3231 Vector<const char> subject_vector = subject->ToAsciiVector();
3232 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003233 if (SearchStringMultiple(isolate,
3234 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003235 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003236 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003237 builder,
3238 &match_pos)) break;
3239 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003240 if (SearchStringMultiple(isolate,
3241 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003242 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003243 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003244 builder,
3245 &match_pos)) break;
3246 }
3247 } else {
3248 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3249 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003250 if (SearchStringMultiple(isolate,
3251 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003252 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003253 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003254 builder,
3255 &match_pos)) break;
3256 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003257 if (SearchStringMultiple(isolate,
3258 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003259 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003260 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003261 builder,
3262 &match_pos)) break;
3263 }
3264 }
3265 }
3266
3267 if (match_pos >= 0) {
3268 SetLastMatchInfoNoCaptures(subject,
3269 last_match_info,
3270 match_pos,
3271 match_pos + pattern->length());
3272 return true;
3273 }
3274 return false; // No matches at all.
3275}
3276
3277
3278static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003279 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003280 Handle<String> subject,
3281 Handle<JSRegExp> regexp,
3282 Handle<JSArray> last_match_array,
3283 FixedArrayBuilder* builder) {
3284 ASSERT(subject->IsFlat());
3285 int match_start = -1;
3286 int match_end = 0;
3287 int pos = 0;
3288 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3289 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3290
3291 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003292 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003293 int subject_length = subject->length();
3294
3295 for (;;) { // Break on failure, return on exception.
3296 RegExpImpl::IrregexpResult result =
3297 RegExpImpl::IrregexpExecOnce(regexp,
3298 subject,
3299 pos,
3300 register_vector);
3301 if (result == RegExpImpl::RE_SUCCESS) {
3302 match_start = register_vector[0];
3303 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3304 if (match_end < match_start) {
3305 ReplacementStringBuilder::AddSubjectSlice(builder,
3306 match_end,
3307 match_start);
3308 }
3309 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003310 HandleScope loop_scope(isolate);
3311 builder->Add(*isolate->factory()->NewSubString(subject,
3312 match_start,
3313 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003314 if (match_start != match_end) {
3315 pos = match_end;
3316 } else {
3317 pos = match_end + 1;
3318 if (pos > subject_length) break;
3319 }
3320 } else if (result == RegExpImpl::RE_FAILURE) {
3321 break;
3322 } else {
3323 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3324 return result;
3325 }
3326 }
3327
3328 if (match_start >= 0) {
3329 if (match_end < subject_length) {
3330 ReplacementStringBuilder::AddSubjectSlice(builder,
3331 match_end,
3332 subject_length);
3333 }
3334 SetLastMatchInfoNoCaptures(subject,
3335 last_match_array,
3336 match_start,
3337 match_end);
3338 return RegExpImpl::RE_SUCCESS;
3339 } else {
3340 return RegExpImpl::RE_FAILURE; // No matches at all.
3341 }
3342}
3343
3344
3345static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003346 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003347 Handle<String> subject,
3348 Handle<JSRegExp> regexp,
3349 Handle<JSArray> last_match_array,
3350 FixedArrayBuilder* builder) {
3351
3352 ASSERT(subject->IsFlat());
3353 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3354 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3355
3356 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003357 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003358
3359 RegExpImpl::IrregexpResult result =
3360 RegExpImpl::IrregexpExecOnce(regexp,
3361 subject,
3362 0,
3363 register_vector);
3364
3365 int capture_count = regexp->CaptureCount();
3366 int subject_length = subject->length();
3367
3368 // Position to search from.
3369 int pos = 0;
3370 // End of previous match. Differs from pos if match was empty.
3371 int match_end = 0;
3372 if (result == RegExpImpl::RE_SUCCESS) {
3373 // Need to keep a copy of the previous match for creating last_match_info
3374 // at the end, so we have two vectors that we swap between.
3375 OffsetsVector registers2(required_registers);
3376 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3377
3378 do {
3379 int match_start = register_vector[0];
3380 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3381 if (match_end < match_start) {
3382 ReplacementStringBuilder::AddSubjectSlice(builder,
3383 match_end,
3384 match_start);
3385 }
3386 match_end = register_vector[1];
3387
3388 {
3389 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003390 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003391 // Arguments array to replace function is match, captures, index and
3392 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003393 Handle<FixedArray> elements =
3394 isolate->factory()->NewFixedArray(3 + capture_count);
3395 Handle<String> match = isolate->factory()->NewSubString(subject,
3396 match_start,
3397 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003398 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003399 for (int i = 1; i <= capture_count; i++) {
3400 int start = register_vector[i * 2];
3401 if (start >= 0) {
3402 int end = register_vector[i * 2 + 1];
3403 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003404 Handle<String> substring = isolate->factory()->NewSubString(subject,
3405 start,
3406 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003407 elements->set(i, *substring);
3408 } else {
3409 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003410 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003411 }
3412 }
3413 elements->set(capture_count + 1, Smi::FromInt(match_start));
3414 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003415 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003416 }
3417 // Swap register vectors, so the last successful match is in
3418 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003419 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003420 prev_register_vector = register_vector;
3421 register_vector = tmp;
3422
3423 if (match_end > match_start) {
3424 pos = match_end;
3425 } else {
3426 pos = match_end + 1;
3427 if (pos > subject_length) {
3428 break;
3429 }
3430 }
3431
3432 result = RegExpImpl::IrregexpExecOnce(regexp,
3433 subject,
3434 pos,
3435 register_vector);
3436 } while (result == RegExpImpl::RE_SUCCESS);
3437
3438 if (result != RegExpImpl::RE_EXCEPTION) {
3439 // Finished matching, with at least one match.
3440 if (match_end < subject_length) {
3441 ReplacementStringBuilder::AddSubjectSlice(builder,
3442 match_end,
3443 subject_length);
3444 }
3445
3446 int last_match_capture_count = (capture_count + 1) * 2;
3447 int last_match_array_size =
3448 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3449 last_match_array->EnsureSize(last_match_array_size);
3450 AssertNoAllocation no_gc;
3451 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3452 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3453 RegExpImpl::SetLastSubject(elements, *subject);
3454 RegExpImpl::SetLastInput(elements, *subject);
3455 for (int i = 0; i < last_match_capture_count; i++) {
3456 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3457 }
3458 return RegExpImpl::RE_SUCCESS;
3459 }
3460 }
3461 // No matches at all, return failure or exception result directly.
3462 return result;
3463}
3464
3465
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003466RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003467 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003468 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003469
3470 CONVERT_ARG_CHECKED(String, subject, 1);
3471 if (!subject->IsFlat()) { FlattenString(subject); }
3472 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3473 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3474 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3475
3476 ASSERT(last_match_info->HasFastElements());
3477 ASSERT(regexp->GetFlags().is_global());
3478 Handle<FixedArray> result_elements;
3479 if (result_array->HasFastElements()) {
3480 result_elements =
3481 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3482 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003483 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003484 }
3485 FixedArrayBuilder builder(result_elements);
3486
3487 if (regexp->TypeTag() == JSRegExp::ATOM) {
3488 Handle<String> pattern(
3489 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003490 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003491 if (SearchStringMultiple(isolate, subject, pattern,
3492 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003493 return *builder.ToJSArray(result_array);
3494 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003495 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003496 }
3497
3498 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3499
3500 RegExpImpl::IrregexpResult result;
3501 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003502 result = SearchRegExpNoCaptureMultiple(isolate,
3503 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003504 regexp,
3505 last_match_info,
3506 &builder);
3507 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003508 result = SearchRegExpMultiple(isolate,
3509 subject,
3510 regexp,
3511 last_match_info,
3512 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003513 }
3514 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003515 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003516 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3517 return Failure::Exception();
3518}
3519
3520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003521RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003522 NoHandleAllocation ha;
3523 ASSERT(args.length() == 2);
3524
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003525 // Fast case where the result is a one character string.
3526 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3527 int value = Smi::cast(args[0])->value();
3528 int radix = Smi::cast(args[1])->value();
3529 if (value >= 0 && value < radix) {
3530 RUNTIME_ASSERT(radix <= 36);
3531 // Character array used for conversion.
3532 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003533 return isolate->heap()->
3534 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003535 }
3536 }
3537
3538 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003539 CONVERT_DOUBLE_CHECKED(value, args[0]);
3540 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003541 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003542 }
3543 if (isinf(value)) {
3544 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003545 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003547 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003548 }
3549 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3550 int radix = FastD2I(radix_number);
3551 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3552 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003553 MaybeObject* result =
3554 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003555 DeleteArray(str);
3556 return result;
3557}
3558
3559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003560RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003561 NoHandleAllocation ha;
3562 ASSERT(args.length() == 2);
3563
3564 CONVERT_DOUBLE_CHECKED(value, args[0]);
3565 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003566 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003567 }
3568 if (isinf(value)) {
3569 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003570 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003571 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003572 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003573 }
3574 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3575 int f = FastD2I(f_number);
3576 RUNTIME_ASSERT(f >= 0);
3577 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003578 MaybeObject* res =
3579 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003580 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003581 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003582}
3583
3584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003585RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003586 NoHandleAllocation ha;
3587 ASSERT(args.length() == 2);
3588
3589 CONVERT_DOUBLE_CHECKED(value, args[0]);
3590 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003591 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 }
3593 if (isinf(value)) {
3594 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003595 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003597 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 }
3599 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3600 int f = FastD2I(f_number);
3601 RUNTIME_ASSERT(f >= -1 && f <= 20);
3602 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003603 MaybeObject* res =
3604 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003605 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003606 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003607}
3608
3609
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003610RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003611 NoHandleAllocation ha;
3612 ASSERT(args.length() == 2);
3613
3614 CONVERT_DOUBLE_CHECKED(value, args[0]);
3615 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003617 }
3618 if (isinf(value)) {
3619 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003620 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003621 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003622 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003623 }
3624 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3625 int f = FastD2I(f_number);
3626 RUNTIME_ASSERT(f >= 1 && f <= 21);
3627 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003628 MaybeObject* res =
3629 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003630 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003631 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003632}
3633
3634
3635// Returns a single character string where first character equals
3636// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003637static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003638 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003639 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003640 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003641 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003643 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003644}
3645
3646
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003647MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3648 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003649 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003650 // Handle [] indexing on Strings
3651 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003652 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3653 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003654 }
3655
3656 // Handle [] indexing on String objects
3657 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003658 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3659 Handle<Object> result =
3660 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3661 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003662 }
3663
3664 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003665 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003666 return prototype->GetElement(index);
3667 }
3668
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003669 return GetElement(object, index);
3670}
3671
3672
lrn@chromium.org303ada72010-10-27 09:33:13 +00003673MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003674 return object->GetElement(index);
3675}
3676
3677
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003678MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3679 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003680 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003681 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003683 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003684 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003685 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003686 isolate->factory()->NewTypeError("non_object_property_load",
3687 HandleVector(args, 2));
3688 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003689 }
3690
3691 // Check if the given key is an array index.
3692 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003693 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003694 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003695 }
3696
3697 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003698 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003699 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003700 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003701 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003702 bool has_pending_exception = false;
3703 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003704 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003705 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003706 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003707 }
3708
ager@chromium.org32912102009-01-16 10:38:43 +00003709 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003710 // the element if so.
3711 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003712 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003713 } else {
3714 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003715 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003716 }
3717}
3718
3719
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003720RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003721 NoHandleAllocation ha;
3722 ASSERT(args.length() == 2);
3723
3724 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003725 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003726
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003727 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728}
3729
3730
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003731// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003732RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003733 NoHandleAllocation ha;
3734 ASSERT(args.length() == 2);
3735
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003736 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003737 // itself.
3738 //
3739 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003740 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003741 // global proxy object never has properties. This is the case
3742 // because the global proxy object forwards everything to its hidden
3743 // prototype including local lookups.
3744 //
3745 // Additionally, we need to make sure that we do not cache results
3746 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003747 if (args[0]->IsJSObject() &&
3748 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003749 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003750 args[1]->IsString()) {
3751 JSObject* receiver = JSObject::cast(args[0]);
3752 String* key = String::cast(args[1]);
3753 if (receiver->HasFastProperties()) {
3754 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003755 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003756 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3757 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003758 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003759 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003760 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003761 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003762 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003763 LookupResult result;
3764 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003765 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003766 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003767 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003768 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003769 }
3770 } else {
3771 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003772 StringDictionary* dictionary = receiver->property_dictionary();
3773 int entry = dictionary->FindEntry(key);
3774 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003775 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003776 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003777 if (!receiver->IsGlobalObject()) return value;
3778 value = JSGlobalPropertyCell::cast(value)->value();
3779 if (!value->IsTheHole()) return value;
3780 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003781 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003782 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003783 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3784 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003785 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003786 Handle<String> str = args.at<String>(0);
3787 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003788 if (index >= 0 && index < str->length()) {
3789 Handle<Object> result = GetCharAt(str, index);
3790 return *result;
3791 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003792 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003793
3794 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003795 return Runtime::GetObjectProperty(isolate,
3796 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003797 args.at<Object>(1));
3798}
3799
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003800// Implements part of 8.12.9 DefineOwnProperty.
3801// There are 3 cases that lead here:
3802// Step 4b - define a new accessor property.
3803// Steps 9c & 12 - replace an existing data property with an accessor property.
3804// Step 12 - update an existing accessor property with an accessor or generic
3805// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003806RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003807 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003808 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003809 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3810 CONVERT_CHECKED(String, name, args[1]);
3811 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003812 Object* fun = args[3];
3813 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003814 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3815 int unchecked = flag_attr->value();
3816 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3817 RUNTIME_ASSERT(!obj->IsNull());
3818 LookupResult result;
3819 obj->LocalLookupRealNamedProperty(name, &result);
3820
3821 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3822 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3823 // delete it to avoid running into trouble in DefineAccessor, which
3824 // handles this incorrectly if the property is readonly (does nothing)
3825 if (result.IsProperty() &&
3826 (result.type() == FIELD || result.type() == NORMAL
3827 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003828 Object* ok;
3829 { MaybeObject* maybe_ok =
3830 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3831 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3832 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003833 }
3834 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3835}
3836
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003837// Implements part of 8.12.9 DefineOwnProperty.
3838// There are 3 cases that lead here:
3839// Step 4a - define a new data property.
3840// Steps 9b & 12 - replace an existing accessor property with a data property.
3841// Step 12 - update an existing data property with a data or generic
3842// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003843RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003844 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003845 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003846 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3847 CONVERT_ARG_CHECKED(String, name, 1);
3848 Handle<Object> obj_value = args.at<Object>(2);
3849
3850 CONVERT_CHECKED(Smi, flag, args[3]);
3851 int unchecked = flag->value();
3852 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3853
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003854 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3855
3856 // Check if this is an element.
3857 uint32_t index;
3858 bool is_element = name->AsArrayIndex(&index);
3859
3860 // Special case for elements if any of the flags are true.
3861 // If elements are in fast case we always implicitly assume that:
3862 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3863 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3864 is_element) {
3865 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003866 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003867 // We do not need to do access checks here since these has already
3868 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003869 Handle<Object> proto(js_object->GetPrototype());
3870 // If proxy is detached, ignore the assignment. Alternatively,
3871 // we could throw an exception.
3872 if (proto->IsNull()) return *obj_value;
3873 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003874 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003875 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003876 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003877 // Make sure that we never go back to fast case.
3878 dictionary->set_requires_slow_elements();
3879 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003880 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003881 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003882 }
3883
ager@chromium.org5c838252010-02-19 08:53:10 +00003884 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003885 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003886
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003887 // To be compatible with safari we do not change the value on API objects
3888 // in defineProperty. Firefox disagrees here, and actually changes the value.
3889 if (result.IsProperty() &&
3890 (result.type() == CALLBACKS) &&
3891 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003892 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003893 }
3894
ager@chromium.org5c838252010-02-19 08:53:10 +00003895 // Take special care when attributes are different and there is already
3896 // a property. For simplicity we normalize the property which enables us
3897 // to not worry about changing the instance_descriptor and creating a new
3898 // map. The current version of SetObjectProperty does not handle attributes
3899 // correctly in the case where a property is a field and is reset with
3900 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003901 if (result.IsProperty() &&
3902 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003903 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003904 if (js_object->IsJSGlobalProxy()) {
3905 // Since the result is a property, the prototype will exist so
3906 // we don't have to check for null.
3907 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003908 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003909 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003910 // Use IgnoreAttributes version since a readonly property may be
3911 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003912 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3913 *obj_value,
3914 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003915 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003916
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003917 return Runtime::ForceSetObjectProperty(isolate,
3918 js_object,
3919 name,
3920 obj_value,
3921 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003922}
3923
3924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003925MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3926 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003927 Handle<Object> key,
3928 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003929 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003930 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003931 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003932
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003934 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003935 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003936 isolate->factory()->NewTypeError("non_object_property_store",
3937 HandleVector(args, 2));
3938 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003939 }
3940
3941 // If the object isn't a JavaScript object, we ignore the store.
3942 if (!object->IsJSObject()) return *value;
3943
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003944 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3945
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946 // Check if the given key is an array index.
3947 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003948 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003949 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3950 // of a string using [] notation. We need to support this too in
3951 // JavaScript.
3952 // In the case of a String object we just need to redirect the assignment to
3953 // the underlying string if the index is in range. Since the underlying
3954 // string does nothing with the assignment then we can ignore such
3955 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003956 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003957 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003958 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003959
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003960 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003961 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003962 return *value;
3963 }
3964
3965 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003966 Handle<Object> result;
3967 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003968 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003970 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003971 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003972 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003973 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003974 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003975 return *value;
3976 }
3977
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979 bool has_pending_exception = false;
3980 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3981 if (has_pending_exception) return Failure::Exception();
3982 Handle<String> name = Handle<String>::cast(converted);
3983
3984 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003985 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003987 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003988 }
3989}
3990
3991
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003992MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
3993 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003994 Handle<Object> key,
3995 Handle<Object> value,
3996 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003997 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003998
3999 // Check if the given key is an array index.
4000 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004001 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004002 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4003 // of a string using [] notation. We need to support this too in
4004 // JavaScript.
4005 // In the case of a String object we just need to redirect the assignment to
4006 // the underlying string if the index is in range. Since the underlying
4007 // string does nothing with the assignment then we can ignore such
4008 // assignments.
4009 if (js_object->IsStringObjectWithCharacterAt(index)) {
4010 return *value;
4011 }
4012
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004013 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004014 }
4015
4016 if (key->IsString()) {
4017 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004018 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004019 } else {
4020 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004021 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004022 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4023 *value,
4024 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004025 }
4026 }
4027
4028 // Call-back into JavaScript to convert the key to a string.
4029 bool has_pending_exception = false;
4030 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4031 if (has_pending_exception) return Failure::Exception();
4032 Handle<String> name = Handle<String>::cast(converted);
4033
4034 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004035 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004036 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004037 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004038 }
4039}
4040
4041
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004042MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4043 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004044 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004045 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004046
4047 // Check if the given key is an array index.
4048 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004049 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004050 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4051 // characters of a string using [] notation. In the case of a
4052 // String object we just need to redirect the deletion to the
4053 // underlying string if the index is in range. Since the
4054 // underlying string does nothing with the deletion, we can ignore
4055 // such deletions.
4056 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004057 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004058 }
4059
4060 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4061 }
4062
4063 Handle<String> key_string;
4064 if (key->IsString()) {
4065 key_string = Handle<String>::cast(key);
4066 } else {
4067 // Call-back into JavaScript to convert the key to a string.
4068 bool has_pending_exception = false;
4069 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4070 if (has_pending_exception) return Failure::Exception();
4071 key_string = Handle<String>::cast(converted);
4072 }
4073
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004074 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004075 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4076}
4077
4078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004079RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004080 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004081 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082
4083 Handle<Object> object = args.at<Object>(0);
4084 Handle<Object> key = args.at<Object>(1);
4085 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004086 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4087 RUNTIME_ASSERT(
4088 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004089 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004090 PropertyAttributes attributes =
4091 static_cast<PropertyAttributes>(unchecked_attributes);
4092
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004093 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004094 if (args.length() == 5) {
4095 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4096 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4097 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004098 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004101 return Runtime::SetObjectProperty(isolate,
4102 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004103 key,
4104 value,
4105 attributes,
4106 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107}
4108
4109
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004110// Set the ES5 native flag on the function.
4111// This is used to decide if we should transform null and undefined
4112// into the global object when doing call and apply.
4113RUNTIME_FUNCTION(MaybeObject*, Runtime_SetES5Flag) {
4114 NoHandleAllocation ha;
4115 RUNTIME_ASSERT(args.length() == 1);
4116
4117 Handle<Object> object = args.at<Object>(0);
4118
4119 if (object->IsJSFunction()) {
4120 JSFunction* func = JSFunction::cast(*object);
4121 func->shared()->set_es5_native(true);
4122 }
4123 return isolate->heap()->undefined_value();
4124}
4125
4126
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127// Set a local property, even if it is READ_ONLY. If the property does not
4128// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004129RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004130 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004131 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 CONVERT_CHECKED(JSObject, object, args[0]);
4133 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004134 // Compute attributes.
4135 PropertyAttributes attributes = NONE;
4136 if (args.length() == 4) {
4137 CONVERT_CHECKED(Smi, value_obj, args[3]);
4138 int unchecked_value = value_obj->value();
4139 // Only attribute bits should be set.
4140 RUNTIME_ASSERT(
4141 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4142 attributes = static_cast<PropertyAttributes>(unchecked_value);
4143 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004144
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004145 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004146 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004147}
4148
4149
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004150RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004151 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004152 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004153
4154 CONVERT_CHECKED(JSObject, object, args[0]);
4155 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004156 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004157 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004158 ? JSObject::STRICT_DELETION
4159 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160}
4161
4162
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004163static Object* HasLocalPropertyImplementation(Isolate* isolate,
4164 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004165 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004166 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004167 // Handle hidden prototypes. If there's a hidden prototype above this thing
4168 // then we have to check it for properties, because they are supposed to
4169 // look like they are on this object.
4170 Handle<Object> proto(object->GetPrototype());
4171 if (proto->IsJSObject() &&
4172 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004173 return HasLocalPropertyImplementation(isolate,
4174 Handle<JSObject>::cast(proto),
4175 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004176 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004177 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004178}
4179
4180
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004181RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004182 NoHandleAllocation ha;
4183 ASSERT(args.length() == 2);
4184 CONVERT_CHECKED(String, key, args[1]);
4185
ager@chromium.org9085a012009-05-11 19:22:57 +00004186 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004188 if (obj->IsJSObject()) {
4189 JSObject* object = JSObject::cast(obj);
4190 // Fast case - no interceptors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004191 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004192 // Slow case. Either it's not there or we have an interceptor. We should
4193 // have handles for this kind of deal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004194 HandleScope scope(isolate);
4195 return HasLocalPropertyImplementation(isolate,
4196 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004197 Handle<String>(key));
4198 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004199 // Well, there is one exception: Handle [] on strings.
4200 uint32_t index;
4201 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004202 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004203 if (index < static_cast<uint32_t>(string->length()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004204 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004205 }
4206 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004207 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208}
4209
4210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004211RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004212 NoHandleAllocation na;
4213 ASSERT(args.length() == 2);
4214
4215 // Only JS objects can have properties.
4216 if (args[0]->IsJSObject()) {
4217 JSObject* object = JSObject::cast(args[0]);
4218 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004219 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004220 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004221 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004222}
4223
4224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004225RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004226 NoHandleAllocation na;
4227 ASSERT(args.length() == 2);
4228
4229 // Only JS objects can have elements.
4230 if (args[0]->IsJSObject()) {
4231 JSObject* object = JSObject::cast(args[0]);
4232 CONVERT_CHECKED(Smi, index_obj, args[1]);
4233 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004234 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004235 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004236 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004237}
4238
4239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004240RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 NoHandleAllocation ha;
4242 ASSERT(args.length() == 2);
4243
4244 CONVERT_CHECKED(JSObject, object, args[0]);
4245 CONVERT_CHECKED(String, key, args[1]);
4246
4247 uint32_t index;
4248 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004249 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004250 }
4251
ager@chromium.org870a0b62008-11-04 11:43:05 +00004252 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004253 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004254}
4255
4256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004257RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004258 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004259 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004260 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004261 return *GetKeysFor(object);
4262}
4263
4264
4265// Returns either a FixedArray as Runtime_GetPropertyNames,
4266// or, if the given object has an enum cache that contains
4267// all enumerable properties of the object and its prototypes
4268// have none, the map of the object. This is used to speed up
4269// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004270RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004271 ASSERT(args.length() == 1);
4272
4273 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4274
4275 if (raw_object->IsSimpleEnum()) return raw_object->map();
4276
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004277 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004278 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004279 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4280 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004281
4282 // Test again, since cache may have been built by preceding call.
4283 if (object->IsSimpleEnum()) return object->map();
4284
4285 return *content;
4286}
4287
4288
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004289// Find the length of the prototype chain that is to to handled as one. If a
4290// prototype object is hidden it is to be viewed as part of the the object it
4291// is prototype for.
4292static int LocalPrototypeChainLength(JSObject* obj) {
4293 int count = 1;
4294 Object* proto = obj->GetPrototype();
4295 while (proto->IsJSObject() &&
4296 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4297 count++;
4298 proto = JSObject::cast(proto)->GetPrototype();
4299 }
4300 return count;
4301}
4302
4303
4304// Return the names of the local named properties.
4305// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004306RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004307 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004308 ASSERT(args.length() == 1);
4309 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004310 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004311 }
4312 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4313
4314 // Skip the global proxy as it has no properties and always delegates to the
4315 // real global object.
4316 if (obj->IsJSGlobalProxy()) {
4317 // Only collect names if access is permitted.
4318 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004319 !isolate->MayNamedAccess(*obj,
4320 isolate->heap()->undefined_value(),
4321 v8::ACCESS_KEYS)) {
4322 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4323 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004324 }
4325 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4326 }
4327
4328 // Find the number of objects making up this.
4329 int length = LocalPrototypeChainLength(*obj);
4330
4331 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004332 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004333 int total_property_count = 0;
4334 Handle<JSObject> jsproto = obj;
4335 for (int i = 0; i < length; i++) {
4336 // Only collect names if access is permitted.
4337 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004338 !isolate->MayNamedAccess(*jsproto,
4339 isolate->heap()->undefined_value(),
4340 v8::ACCESS_KEYS)) {
4341 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4342 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004343 }
4344 int n;
4345 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4346 local_property_count[i] = n;
4347 total_property_count += n;
4348 if (i < length - 1) {
4349 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4350 }
4351 }
4352
4353 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004354 Handle<FixedArray> names =
4355 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004356
4357 // Get the property names.
4358 jsproto = obj;
4359 int proto_with_hidden_properties = 0;
4360 for (int i = 0; i < length; i++) {
4361 jsproto->GetLocalPropertyNames(*names,
4362 i == 0 ? 0 : local_property_count[i - 1]);
4363 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4364 proto_with_hidden_properties++;
4365 }
4366 if (i < length - 1) {
4367 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4368 }
4369 }
4370
4371 // Filter out name of hidden propeties object.
4372 if (proto_with_hidden_properties > 0) {
4373 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004374 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004375 names->length() - proto_with_hidden_properties);
4376 int dest_pos = 0;
4377 for (int i = 0; i < total_property_count; i++) {
4378 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004379 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004380 continue;
4381 }
4382 names->set(dest_pos++, name);
4383 }
4384 }
4385
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004386 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004387}
4388
4389
4390// Return the names of the local indexed properties.
4391// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004392RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004393 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004394 ASSERT(args.length() == 1);
4395 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004396 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004397 }
4398 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4399
4400 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004401 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004402 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004403 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004404}
4405
4406
4407// Return information on whether an object has a named or indexed interceptor.
4408// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004409RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004410 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004411 ASSERT(args.length() == 1);
4412 if (!args[0]->IsJSObject()) {
4413 return Smi::FromInt(0);
4414 }
4415 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4416
4417 int result = 0;
4418 if (obj->HasNamedInterceptor()) result |= 2;
4419 if (obj->HasIndexedInterceptor()) result |= 1;
4420
4421 return Smi::FromInt(result);
4422}
4423
4424
4425// Return property names from named interceptor.
4426// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004427RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004428 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004429 ASSERT(args.length() == 1);
4430 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4431
4432 if (obj->HasNamedInterceptor()) {
4433 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4434 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4435 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004436 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004437}
4438
4439
4440// Return element names from indexed interceptor.
4441// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004442RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004443 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004444 ASSERT(args.length() == 1);
4445 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4446
4447 if (obj->HasIndexedInterceptor()) {
4448 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4449 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4450 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004451 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004452}
4453
4454
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004455RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004456 ASSERT_EQ(args.length(), 1);
4457 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004458 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004459 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004460
4461 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004462 // Do access checks before going to the global object.
4463 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004464 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004465 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004466 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4467 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004468 }
4469
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004470 Handle<Object> proto(object->GetPrototype());
4471 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004472 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004473 object = Handle<JSObject>::cast(proto);
4474 }
4475
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004476 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4477 LOCAL_ONLY);
4478 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4479 // property array and since the result is mutable we have to create
4480 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004481 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004482 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004483 for (int i = 0; i < length; i++) {
4484 Object* entry = contents->get(i);
4485 if (entry->IsString()) {
4486 copy->set(i, entry);
4487 } else {
4488 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004489 HandleScope scope(isolate);
4490 Handle<Object> entry_handle(entry, isolate);
4491 Handle<Object> entry_str =
4492 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004493 copy->set(i, *entry_str);
4494 }
4495 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004496 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004497}
4498
4499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004500RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004501 NoHandleAllocation ha;
4502 ASSERT(args.length() == 1);
4503
4504 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004505 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004506 it.AdvanceToArgumentsFrame();
4507 JavaScriptFrame* frame = it.frame();
4508
4509 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004510 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004511
4512 // Try to convert the key to an index. If successful and within
4513 // index return the the argument from the frame.
4514 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004515 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004516 return frame->GetParameter(index);
4517 }
4518
4519 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004520 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521 bool exception = false;
4522 Handle<Object> converted =
4523 Execution::ToString(args.at<Object>(0), &exception);
4524 if (exception) return Failure::Exception();
4525 Handle<String> key = Handle<String>::cast(converted);
4526
4527 // Try to convert the string key into an array index.
4528 if (key->AsArrayIndex(&index)) {
4529 if (index < n) {
4530 return frame->GetParameter(index);
4531 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004532 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533 }
4534 }
4535
4536 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004537 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4538 if (key->Equals(isolate->heap()->callee_symbol())) {
4539 Object* function = frame->function();
4540 if (function->IsJSFunction() &&
4541 JSFunction::cast(function)->shared()->strict_mode()) {
4542 return isolate->Throw(*isolate->factory()->NewTypeError(
4543 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4544 }
4545 return function;
4546 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004547
4548 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004549 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004550}
4551
4552
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004553RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004554 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004555
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004556 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004557 Handle<Object> object = args.at<Object>(0);
4558 if (object->IsJSObject()) {
4559 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004560 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004561 MaybeObject* ok = js_object->TransformToFastProperties(0);
4562 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004563 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004564 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004565 return *object;
4566}
4567
4568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004569RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004570 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004571
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004572 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004573 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004574 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004575 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004576 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004577 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004578 return *object;
4579}
4580
4581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004582RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004583 NoHandleAllocation ha;
4584 ASSERT(args.length() == 1);
4585
4586 return args[0]->ToBoolean();
4587}
4588
4589
4590// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4591// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004592RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593 NoHandleAllocation ha;
4594
4595 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004596 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004597 HeapObject* heap_obj = HeapObject::cast(obj);
4598
4599 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004600 if (heap_obj->map()->is_undetectable()) {
4601 return isolate->heap()->undefined_symbol();
4602 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603
4604 InstanceType instance_type = heap_obj->map()->instance_type();
4605 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004606 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004607 }
4608
4609 switch (instance_type) {
4610 case ODDBALL_TYPE:
4611 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004612 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004613 }
4614 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004615 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616 }
4617 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004618 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004619 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004620 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004621 default:
4622 // For any kind of object not handled above, the spec rule for
4623 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004624 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004625 }
4626}
4627
4628
lrn@chromium.org25156de2010-04-06 13:10:27 +00004629static bool AreDigits(const char*s, int from, int to) {
4630 for (int i = from; i < to; i++) {
4631 if (s[i] < '0' || s[i] > '9') return false;
4632 }
4633
4634 return true;
4635}
4636
4637
4638static int ParseDecimalInteger(const char*s, int from, int to) {
4639 ASSERT(to - from < 10); // Overflow is not possible.
4640 ASSERT(from < to);
4641 int d = s[from] - '0';
4642
4643 for (int i = from + 1; i < to; i++) {
4644 d = 10 * d + (s[i] - '0');
4645 }
4646
4647 return d;
4648}
4649
4650
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004651RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004652 NoHandleAllocation ha;
4653 ASSERT(args.length() == 1);
4654 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004655 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004656
4657 // Fast case: short integer or some sorts of junk values.
4658 int len = subject->length();
4659 if (subject->IsSeqAsciiString()) {
4660 if (len == 0) return Smi::FromInt(0);
4661
4662 char const* data = SeqAsciiString::cast(subject)->GetChars();
4663 bool minus = (data[0] == '-');
4664 int start_pos = (minus ? 1 : 0);
4665
4666 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004667 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004668 } else if (data[start_pos] > '9') {
4669 // Fast check for a junk value. A valid string may start from a
4670 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4671 // the 'I' character ('Infinity'). All of that have codes not greater than
4672 // '9' except 'I'.
4673 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004674 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004675 }
4676 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4677 // The maximal/minimal smi has 10 digits. If the string has less digits we
4678 // know it will fit into the smi-data type.
4679 int d = ParseDecimalInteger(data, start_pos, len);
4680 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004681 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004682 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004683 } else if (!subject->HasHashCode() &&
4684 len <= String::kMaxArrayIndexSize &&
4685 (len == 1 || data[0] != '0')) {
4686 // String hash is not calculated yet but all the data are present.
4687 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004688 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004689#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004690 subject->Hash(); // Force hash calculation.
4691 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4692 static_cast<int>(hash));
4693#endif
4694 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004695 }
4696 return Smi::FromInt(d);
4697 }
4698 }
4699
4700 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004701 return isolate->heap()->NumberFromDouble(
4702 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004703}
4704
4705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004706RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004707 NoHandleAllocation ha;
4708 ASSERT(args.length() == 1);
4709
4710 CONVERT_CHECKED(JSArray, codes, args[0]);
4711 int length = Smi::cast(codes->length())->value();
4712
4713 // Check if the string can be ASCII.
4714 int i;
4715 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004716 Object* element;
4717 { MaybeObject* maybe_element = codes->GetElement(i);
4718 // We probably can't get an exception here, but just in order to enforce
4719 // the checking of inputs in the runtime calls we check here.
4720 if (!maybe_element->ToObject(&element)) return maybe_element;
4721 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4723 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4724 break;
4725 }
4726
lrn@chromium.org303ada72010-10-27 09:33:13 +00004727 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004728 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004729 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004730 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004731 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004732 }
4733
lrn@chromium.org303ada72010-10-27 09:33:13 +00004734 Object* object = NULL;
4735 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004736 String* result = String::cast(object);
4737 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004738 Object* element;
4739 { MaybeObject* maybe_element = codes->GetElement(i);
4740 if (!maybe_element->ToObject(&element)) return maybe_element;
4741 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004743 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004744 }
4745 return result;
4746}
4747
4748
4749// kNotEscaped is generated by the following:
4750//
4751// #!/bin/perl
4752// for (my $i = 0; $i < 256; $i++) {
4753// print "\n" if $i % 16 == 0;
4754// my $c = chr($i);
4755// my $escaped = 1;
4756// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4757// print $escaped ? "0, " : "1, ";
4758// }
4759
4760
4761static bool IsNotEscaped(uint16_t character) {
4762 // Only for 8 bit characters, the rest are always escaped (in a different way)
4763 ASSERT(character < 256);
4764 static const char kNotEscaped[256] = {
4765 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4766 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4767 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4768 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4769 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4770 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4771 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4772 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4773 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4774 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4775 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4776 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4777 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4778 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4779 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4780 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4781 };
4782 return kNotEscaped[character] != 0;
4783}
4784
4785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004786RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004787 const char hex_chars[] = "0123456789ABCDEF";
4788 NoHandleAllocation ha;
4789 ASSERT(args.length() == 1);
4790 CONVERT_CHECKED(String, source, args[0]);
4791
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004792 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004793
4794 int escaped_length = 0;
4795 int length = source->length();
4796 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004797 Access<StringInputBuffer> buffer(
4798 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004799 buffer->Reset(source);
4800 while (buffer->has_more()) {
4801 uint16_t character = buffer->GetNext();
4802 if (character >= 256) {
4803 escaped_length += 6;
4804 } else if (IsNotEscaped(character)) {
4805 escaped_length++;
4806 } else {
4807 escaped_length += 3;
4808 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004809 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004810 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004811 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004812 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004813 return Failure::OutOfMemoryException();
4814 }
4815 }
4816 }
4817 // No length change implies no change. Return original string if no change.
4818 if (escaped_length == length) {
4819 return source;
4820 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004821 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004822 { MaybeObject* maybe_o =
4823 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004824 if (!maybe_o->ToObject(&o)) return maybe_o;
4825 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004826 String* destination = String::cast(o);
4827 int dest_position = 0;
4828
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004829 Access<StringInputBuffer> buffer(
4830 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 buffer->Rewind();
4832 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004833 uint16_t chr = buffer->GetNext();
4834 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004835 destination->Set(dest_position, '%');
4836 destination->Set(dest_position+1, 'u');
4837 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4838 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4839 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4840 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004841 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004842 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004843 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004844 dest_position++;
4845 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004846 destination->Set(dest_position, '%');
4847 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4848 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004849 dest_position += 3;
4850 }
4851 }
4852 return destination;
4853}
4854
4855
4856static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4857 static const signed char kHexValue['g'] = {
4858 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4859 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4860 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4861 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4862 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4863 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4864 -1, 10, 11, 12, 13, 14, 15 };
4865
4866 if (character1 > 'f') return -1;
4867 int hi = kHexValue[character1];
4868 if (hi == -1) return -1;
4869 if (character2 > 'f') return -1;
4870 int lo = kHexValue[character2];
4871 if (lo == -1) return -1;
4872 return (hi << 4) + lo;
4873}
4874
4875
ager@chromium.org870a0b62008-11-04 11:43:05 +00004876static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004877 int i,
4878 int length,
4879 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004880 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004881 int32_t hi = 0;
4882 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004883 if (character == '%' &&
4884 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004885 source->Get(i + 1) == 'u' &&
4886 (hi = TwoDigitHex(source->Get(i + 2),
4887 source->Get(i + 3))) != -1 &&
4888 (lo = TwoDigitHex(source->Get(i + 4),
4889 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004890 *step = 6;
4891 return (hi << 8) + lo;
4892 } else if (character == '%' &&
4893 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004894 (lo = TwoDigitHex(source->Get(i + 1),
4895 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004896 *step = 3;
4897 return lo;
4898 } else {
4899 *step = 1;
4900 return character;
4901 }
4902}
4903
4904
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004905RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004906 NoHandleAllocation ha;
4907 ASSERT(args.length() == 1);
4908 CONVERT_CHECKED(String, source, args[0]);
4909
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004910 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004911
4912 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004913 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004914
4915 int unescaped_length = 0;
4916 for (int i = 0; i < length; unescaped_length++) {
4917 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004918 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004919 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004920 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004921 i += step;
4922 }
4923
4924 // No length change implies no change. Return original string if no change.
4925 if (unescaped_length == length)
4926 return source;
4927
lrn@chromium.org303ada72010-10-27 09:33:13 +00004928 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004929 { MaybeObject* maybe_o =
4930 ascii ?
4931 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4932 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004933 if (!maybe_o->ToObject(&o)) return maybe_o;
4934 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004935 String* destination = String::cast(o);
4936
4937 int dest_position = 0;
4938 for (int i = 0; i < length; dest_position++) {
4939 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004940 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004941 i += step;
4942 }
4943 return destination;
4944}
4945
4946
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004947static const unsigned int kQuoteTableLength = 128u;
4948
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004949static const int kJsonQuotesCharactersPerEntry = 8;
4950static const char* const JsonQuotes =
4951 "\\u0000 \\u0001 \\u0002 \\u0003 "
4952 "\\u0004 \\u0005 \\u0006 \\u0007 "
4953 "\\b \\t \\n \\u000b "
4954 "\\f \\r \\u000e \\u000f "
4955 "\\u0010 \\u0011 \\u0012 \\u0013 "
4956 "\\u0014 \\u0015 \\u0016 \\u0017 "
4957 "\\u0018 \\u0019 \\u001a \\u001b "
4958 "\\u001c \\u001d \\u001e \\u001f "
4959 " ! \\\" # "
4960 "$ % & ' "
4961 "( ) * + "
4962 ", - . / "
4963 "0 1 2 3 "
4964 "4 5 6 7 "
4965 "8 9 : ; "
4966 "< = > ? "
4967 "@ A B C "
4968 "D E F G "
4969 "H I J K "
4970 "L M N O "
4971 "P Q R S "
4972 "T U V W "
4973 "X Y Z [ "
4974 "\\\\ ] ^ _ "
4975 "` a b c "
4976 "d e f g "
4977 "h i j k "
4978 "l m n o "
4979 "p q r s "
4980 "t u v w "
4981 "x y z { "
4982 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004983
4984
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004985// For a string that is less than 32k characters it should always be
4986// possible to allocate it in new space.
4987static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4988
4989
4990// Doing JSON quoting cannot make the string more than this many times larger.
4991static const int kJsonQuoteWorstCaseBlowup = 6;
4992
4993
4994// Covers the entire ASCII range (all other characters are unchanged by JSON
4995// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004996static const byte JsonQuoteLengths[kQuoteTableLength] = {
4997 6, 6, 6, 6, 6, 6, 6, 6,
4998 2, 2, 2, 6, 2, 2, 6, 6,
4999 6, 6, 6, 6, 6, 6, 6, 6,
5000 6, 6, 6, 6, 6, 6, 6, 6,
5001 1, 1, 2, 1, 1, 1, 1, 1,
5002 1, 1, 1, 1, 1, 1, 1, 1,
5003 1, 1, 1, 1, 1, 1, 1, 1,
5004 1, 1, 1, 1, 1, 1, 1, 1,
5005 1, 1, 1, 1, 1, 1, 1, 1,
5006 1, 1, 1, 1, 1, 1, 1, 1,
5007 1, 1, 1, 1, 1, 1, 1, 1,
5008 1, 1, 1, 1, 2, 1, 1, 1,
5009 1, 1, 1, 1, 1, 1, 1, 1,
5010 1, 1, 1, 1, 1, 1, 1, 1,
5011 1, 1, 1, 1, 1, 1, 1, 1,
5012 1, 1, 1, 1, 1, 1, 1, 1,
5013};
5014
5015
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005016template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005017MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005018
5019
5020template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005021MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5022 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005023}
5024
5025
5026template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005027MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5028 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005029}
5030
5031
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005032template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005033static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5034 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005035 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005036 const Char* read_cursor = characters.start();
5037 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005038 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005039 int quoted_length = kSpaceForQuotes;
5040 while (read_cursor < end) {
5041 Char c = *(read_cursor++);
5042 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5043 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005044 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005045 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005046 }
5047 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005048 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5049 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005050 Object* new_object;
5051 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005052 return new_alloc;
5053 }
5054 StringType* new_string = StringType::cast(new_object);
5055
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005056 Char* write_cursor = reinterpret_cast<Char*>(
5057 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005058 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005059 *(write_cursor++) = '"';
5060
5061 read_cursor = characters.start();
5062 while (read_cursor < end) {
5063 Char c = *(read_cursor++);
5064 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5065 *(write_cursor++) = c;
5066 } else {
5067 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5068 const char* replacement = JsonQuotes +
5069 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5070 for (int i = 0; i < len; i++) {
5071 *write_cursor++ = *replacement++;
5072 }
5073 }
5074 }
5075 *(write_cursor++) = '"';
5076 return new_string;
5077}
5078
5079
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005080template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005081static MaybeObject* QuoteJsonString(Isolate* isolate,
5082 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005083 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005084 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005085 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005086 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5087 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005088 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005089 }
5090
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005091 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5092 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005093 Object* new_object;
5094 if (!new_alloc->ToObject(&new_object)) {
5095 return new_alloc;
5096 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005097 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005098 // Even if our string is small enough to fit in new space we still have to
5099 // handle it being allocated in old space as may happen in the third
5100 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5101 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005102 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005103 }
5104 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005105 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005106
5107 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5108 Char* write_cursor = reinterpret_cast<Char*>(
5109 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005110 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005111 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005112
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005113 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005114 const Char* end = read_cursor + length;
5115 while (read_cursor < end) {
5116 Char c = *(read_cursor++);
5117 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5118 *(write_cursor++) = c;
5119 } else {
5120 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5121 const char* replacement = JsonQuotes +
5122 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5123 write_cursor[0] = replacement[0];
5124 if (len > 1) {
5125 write_cursor[1] = replacement[1];
5126 if (len > 2) {
5127 ASSERT(len == 6);
5128 write_cursor[2] = replacement[2];
5129 write_cursor[3] = replacement[3];
5130 write_cursor[4] = replacement[4];
5131 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005132 }
5133 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005134 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005135 }
5136 }
5137 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005138
5139 int final_length = static_cast<int>(
5140 write_cursor - reinterpret_cast<Char*>(
5141 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005142 isolate->heap()->new_space()->
5143 template ShrinkStringAtAllocationBoundary<StringType>(
5144 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005145 return new_string;
5146}
5147
5148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005149RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005150 NoHandleAllocation ha;
5151 CONVERT_CHECKED(String, str, args[0]);
5152 if (!str->IsFlat()) {
5153 MaybeObject* try_flatten = str->TryFlatten();
5154 Object* flat;
5155 if (!try_flatten->ToObject(&flat)) {
5156 return try_flatten;
5157 }
5158 str = String::cast(flat);
5159 ASSERT(str->IsFlat());
5160 }
5161 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005162 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5163 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005164 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5166 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005167 }
5168}
5169
5170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005171RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005172 NoHandleAllocation ha;
5173 CONVERT_CHECKED(String, str, args[0]);
5174 if (!str->IsFlat()) {
5175 MaybeObject* try_flatten = str->TryFlatten();
5176 Object* flat;
5177 if (!try_flatten->ToObject(&flat)) {
5178 return try_flatten;
5179 }
5180 str = String::cast(flat);
5181 ASSERT(str->IsFlat());
5182 }
5183 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005184 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5185 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005186 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005187 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5188 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005189 }
5190}
5191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005192RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005193 NoHandleAllocation ha;
5194
5195 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005196 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005197
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005198 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005199
lrn@chromium.org25156de2010-04-06 13:10:27 +00005200 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005201 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005202 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005203}
5204
5205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005206RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005207 NoHandleAllocation ha;
5208 CONVERT_CHECKED(String, str, args[0]);
5209
5210 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005211 double value = StringToDouble(isolate->unicode_cache(),
5212 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005213
5214 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005216}
5217
5218
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005219template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005220MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005221 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005222 String* s,
5223 int length,
5224 int input_string_length,
5225 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005226 // We try this twice, once with the assumption that the result is no longer
5227 // than the input and, if that assumption breaks, again with the exact
5228 // length. This may not be pretty, but it is nicer than what was here before
5229 // and I hereby claim my vaffel-is.
5230 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005231 // Allocate the resulting string.
5232 //
5233 // NOTE: This assumes that the upper/lower case of an ascii
5234 // character is also ascii. This is currently the case, but it
5235 // might break in the future if we implement more context and locale
5236 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005237 Object* o;
5238 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005239 ? isolate->heap()->AllocateRawAsciiString(length)
5240 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005241 if (!maybe_o->ToObject(&o)) return maybe_o;
5242 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005243 String* result = String::cast(o);
5244 bool has_changed_character = false;
5245
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005246 // Convert all characters to upper case, assuming that they will fit
5247 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005248 Access<StringInputBuffer> buffer(
5249 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005250 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005251 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005252 // We can assume that the string is not empty
5253 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005254 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005255 bool has_next = buffer->has_more();
5256 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005257 int char_length = mapping->get(current, next, chars);
5258 if (char_length == 0) {
5259 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005260 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005261 i++;
5262 } else if (char_length == 1) {
5263 // Common case: converting the letter resulted in one character.
5264 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005265 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005266 has_changed_character = true;
5267 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005268 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005269 // We've assumed that the result would be as long as the
5270 // input but here is a character that converts to several
5271 // characters. No matter, we calculate the exact length
5272 // of the result and try the whole thing again.
5273 //
5274 // Note that this leaves room for optimization. We could just
5275 // memcpy what we already have to the result string. Also,
5276 // the result string is the last object allocated we could
5277 // "realloc" it and probably, in the vast majority of cases,
5278 // extend the existing string to be able to hold the full
5279 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005280 int next_length = 0;
5281 if (has_next) {
5282 next_length = mapping->get(next, 0, chars);
5283 if (next_length == 0) next_length = 1;
5284 }
5285 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005286 while (buffer->has_more()) {
5287 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005288 // NOTE: we use 0 as the next character here because, while
5289 // the next character may affect what a character converts to,
5290 // it does not in any case affect the length of what it convert
5291 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005292 int char_length = mapping->get(current, 0, chars);
5293 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005294 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005295 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005296 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005297 return Failure::OutOfMemoryException();
5298 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005299 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005300 // Try again with the real length.
5301 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005302 } else {
5303 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005304 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005305 i++;
5306 }
5307 has_changed_character = true;
5308 }
5309 current = next;
5310 }
5311 if (has_changed_character) {
5312 return result;
5313 } else {
5314 // If we didn't actually change anything in doing the conversion
5315 // we simple return the result and let the converted string
5316 // become garbage; there is no reason to keep two identical strings
5317 // alive.
5318 return s;
5319 }
5320}
5321
5322
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005323namespace {
5324
lrn@chromium.org303ada72010-10-27 09:33:13 +00005325static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5326
5327
5328// Given a word and two range boundaries returns a word with high bit
5329// set in every byte iff the corresponding input byte was strictly in
5330// the range (m, n). All the other bits in the result are cleared.
5331// This function is only useful when it can be inlined and the
5332// boundaries are statically known.
5333// Requires: all bytes in the input word and the boundaries must be
5334// ascii (less than 0x7F).
5335static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5336 // Every byte in an ascii string is less than or equal to 0x7F.
5337 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5338 // Use strict inequalities since in edge cases the function could be
5339 // further simplified.
5340 ASSERT(0 < m && m < n && n < 0x7F);
5341 // Has high bit set in every w byte less than n.
5342 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5343 // Has high bit set in every w byte greater than m.
5344 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5345 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5346}
5347
5348
5349enum AsciiCaseConversion {
5350 ASCII_TO_LOWER,
5351 ASCII_TO_UPPER
5352};
5353
5354
5355template <AsciiCaseConversion dir>
5356struct FastAsciiConverter {
5357 static bool Convert(char* dst, char* src, int length) {
5358#ifdef DEBUG
5359 char* saved_dst = dst;
5360 char* saved_src = src;
5361#endif
5362 // We rely on the distance between upper and lower case letters
5363 // being a known power of 2.
5364 ASSERT('a' - 'A' == (1 << 5));
5365 // Boundaries for the range of input characters than require conversion.
5366 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5367 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5368 bool changed = false;
5369 char* const limit = src + length;
5370#ifdef V8_HOST_CAN_READ_UNALIGNED
5371 // Process the prefix of the input that requires no conversion one
5372 // (machine) word at a time.
5373 while (src <= limit - sizeof(uintptr_t)) {
5374 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5375 if (AsciiRangeMask(w, lo, hi) != 0) {
5376 changed = true;
5377 break;
5378 }
5379 *reinterpret_cast<uintptr_t*>(dst) = w;
5380 src += sizeof(uintptr_t);
5381 dst += sizeof(uintptr_t);
5382 }
5383 // Process the remainder of the input performing conversion when
5384 // required one word at a time.
5385 while (src <= limit - sizeof(uintptr_t)) {
5386 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5387 uintptr_t m = AsciiRangeMask(w, lo, hi);
5388 // The mask has high (7th) bit set in every byte that needs
5389 // conversion and we know that the distance between cases is
5390 // 1 << 5.
5391 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5392 src += sizeof(uintptr_t);
5393 dst += sizeof(uintptr_t);
5394 }
5395#endif
5396 // Process the last few bytes of the input (or the whole input if
5397 // unaligned access is not supported).
5398 while (src < limit) {
5399 char c = *src;
5400 if (lo < c && c < hi) {
5401 c ^= (1 << 5);
5402 changed = true;
5403 }
5404 *dst = c;
5405 ++src;
5406 ++dst;
5407 }
5408#ifdef DEBUG
5409 CheckConvert(saved_dst, saved_src, length, changed);
5410#endif
5411 return changed;
5412 }
5413
5414#ifdef DEBUG
5415 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5416 bool expected_changed = false;
5417 for (int i = 0; i < length; i++) {
5418 if (dst[i] == src[i]) continue;
5419 expected_changed = true;
5420 if (dir == ASCII_TO_LOWER) {
5421 ASSERT('A' <= src[i] && src[i] <= 'Z');
5422 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5423 } else {
5424 ASSERT(dir == ASCII_TO_UPPER);
5425 ASSERT('a' <= src[i] && src[i] <= 'z');
5426 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5427 }
5428 }
5429 ASSERT(expected_changed == changed);
5430 }
5431#endif
5432};
5433
5434
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005435struct ToLowerTraits {
5436 typedef unibrow::ToLowercase UnibrowConverter;
5437
lrn@chromium.org303ada72010-10-27 09:33:13 +00005438 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005439};
5440
5441
5442struct ToUpperTraits {
5443 typedef unibrow::ToUppercase UnibrowConverter;
5444
lrn@chromium.org303ada72010-10-27 09:33:13 +00005445 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005446};
5447
5448} // namespace
5449
5450
5451template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005452MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005453 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005454 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005455 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005456 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005457 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005458 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005459
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005460 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005461 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005462 if (length == 0) return s;
5463
5464 // Simpler handling of ascii strings.
5465 //
5466 // NOTE: This assumes that the upper/lower case of an ascii
5467 // character is also ascii. This is currently the case, but it
5468 // might break in the future if we implement more context and locale
5469 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005470 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005471 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005472 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005473 if (!maybe_o->ToObject(&o)) return maybe_o;
5474 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005475 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005476 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005477 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005478 return has_changed_character ? result : s;
5479 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005480
lrn@chromium.org303ada72010-10-27 09:33:13 +00005481 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005482 { MaybeObject* maybe_answer =
5483 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005484 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5485 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005486 if (answer->IsSmi()) {
5487 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005488 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005489 ConvertCaseHelper(isolate,
5490 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005491 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5492 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005493 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005494 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005495}
5496
5497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005498RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005499 return ConvertCase<ToLowerTraits>(
5500 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501}
5502
5503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005504RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005505 return ConvertCase<ToUpperTraits>(
5506 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005507}
5508
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005509
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005510static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5511 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5512}
5513
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005515RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005516 NoHandleAllocation ha;
5517 ASSERT(args.length() == 3);
5518
5519 CONVERT_CHECKED(String, s, args[0]);
5520 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5521 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5522
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005523 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005524 int length = s->length();
5525
5526 int left = 0;
5527 if (trimLeft) {
5528 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5529 left++;
5530 }
5531 }
5532
5533 int right = length;
5534 if (trimRight) {
5535 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5536 right--;
5537 }
5538 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005539 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005540}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005541
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005542
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005543template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005544void FindStringIndices(Isolate* isolate,
5545 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005546 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005547 ZoneList<int>* indices,
5548 unsigned int limit) {
5549 ASSERT(limit > 0);
5550 // Collect indices of pattern in subject, and the end-of-string index.
5551 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005552 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005553 int pattern_length = pattern.length();
5554 int index = 0;
5555 while (limit > 0) {
5556 index = search.Search(subject, index);
5557 if (index < 0) return;
5558 indices->Add(index);
5559 index += pattern_length;
5560 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005561 }
5562}
5563
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005565RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005566 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005567 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005568 CONVERT_ARG_CHECKED(String, subject, 0);
5569 CONVERT_ARG_CHECKED(String, pattern, 1);
5570 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5571
5572 int subject_length = subject->length();
5573 int pattern_length = pattern->length();
5574 RUNTIME_ASSERT(pattern_length > 0);
5575
5576 // The limit can be very large (0xffffffffu), but since the pattern
5577 // isn't empty, we can never create more parts than ~half the length
5578 // of the subject.
5579
5580 if (!subject->IsFlat()) FlattenString(subject);
5581
5582 static const int kMaxInitialListCapacity = 16;
5583
5584 ZoneScope scope(DELETE_ON_EXIT);
5585
5586 // Find (up to limit) indices of separator and end-of-string in subject
5587 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5588 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005589 if (!pattern->IsFlat()) FlattenString(pattern);
5590
5591 // No allocation block.
5592 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005593 AssertNoAllocation nogc;
5594 if (subject->IsAsciiRepresentation()) {
5595 Vector<const char> subject_vector = subject->ToAsciiVector();
5596 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005597 FindStringIndices(isolate,
5598 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005599 pattern->ToAsciiVector(),
5600 &indices,
5601 limit);
5602 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005603 FindStringIndices(isolate,
5604 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005605 pattern->ToUC16Vector(),
5606 &indices,
5607 limit);
5608 }
5609 } else {
5610 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5611 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005612 FindStringIndices(isolate,
5613 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005614 pattern->ToAsciiVector(),
5615 &indices,
5616 limit);
5617 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005618 FindStringIndices(isolate,
5619 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005620 pattern->ToUC16Vector(),
5621 &indices,
5622 limit);
5623 }
5624 }
5625 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005626
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005627 if (static_cast<uint32_t>(indices.length()) < limit) {
5628 indices.Add(subject_length);
5629 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005630
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005631 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005632
5633 // Create JSArray of substrings separated by separator.
5634 int part_count = indices.length();
5635
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005636 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005637 result->set_length(Smi::FromInt(part_count));
5638
5639 ASSERT(result->HasFastElements());
5640
5641 if (part_count == 1 && indices.at(0) == subject_length) {
5642 FixedArray::cast(result->elements())->set(0, *subject);
5643 return *result;
5644 }
5645
5646 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5647 int part_start = 0;
5648 for (int i = 0; i < part_count; i++) {
5649 HandleScope local_loop_handle;
5650 int part_end = indices.at(i);
5651 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005652 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005653 elements->set(i, *substring);
5654 part_start = part_end + pattern_length;
5655 }
5656
5657 return *result;
5658}
5659
5660
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005661// Copies ascii characters to the given fixed array looking up
5662// one-char strings in the cache. Gives up on the first char that is
5663// not in the cache and fills the remainder with smi zeros. Returns
5664// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005665static int CopyCachedAsciiCharsToArray(Heap* heap,
5666 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005667 FixedArray* elements,
5668 int length) {
5669 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005670 FixedArray* ascii_cache = heap->single_character_string_cache();
5671 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005672 int i;
5673 for (i = 0; i < length; ++i) {
5674 Object* value = ascii_cache->get(chars[i]);
5675 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005676 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005677 elements->set(i, value, SKIP_WRITE_BARRIER);
5678 }
5679 if (i < length) {
5680 ASSERT(Smi::FromInt(0) == 0);
5681 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5682 }
5683#ifdef DEBUG
5684 for (int j = 0; j < length; ++j) {
5685 Object* element = elements->get(j);
5686 ASSERT(element == Smi::FromInt(0) ||
5687 (element->IsString() && String::cast(element)->LooksValid()));
5688 }
5689#endif
5690 return i;
5691}
5692
5693
5694// Converts a String to JSArray.
5695// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005696RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005697 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005698 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005699 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005700 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005701
5702 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005703 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005704
5705 Handle<FixedArray> elements;
5706 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005707 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005708 { MaybeObject* maybe_obj =
5709 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005710 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5711 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005712 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005713
5714 Vector<const char> chars = s->ToAsciiVector();
5715 // Note, this will initialize all elements (not only the prefix)
5716 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005717 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5718 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005719 *elements,
5720 length);
5721
5722 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005723 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5724 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005725 }
5726 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005727 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005728 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005729 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5730 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005731 }
5732 }
5733
5734#ifdef DEBUG
5735 for (int i = 0; i < length; ++i) {
5736 ASSERT(String::cast(elements->get(i))->length() == 1);
5737 }
5738#endif
5739
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005740 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005741}
5742
5743
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005744RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005745 NoHandleAllocation ha;
5746 ASSERT(args.length() == 1);
5747 CONVERT_CHECKED(String, value, args[0]);
5748 return value->ToObject();
5749}
5750
5751
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005752bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005753 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005754 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005755 return char_length == 0;
5756}
5757
5758
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005759RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005760 NoHandleAllocation ha;
5761 ASSERT(args.length() == 1);
5762
5763 Object* number = args[0];
5764 RUNTIME_ASSERT(number->IsNumber());
5765
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005766 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005767}
5768
5769
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005770RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005771 NoHandleAllocation ha;
5772 ASSERT(args.length() == 1);
5773
5774 Object* number = args[0];
5775 RUNTIME_ASSERT(number->IsNumber());
5776
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005777 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005778}
5779
5780
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005781RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005782 NoHandleAllocation ha;
5783 ASSERT(args.length() == 1);
5784
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005785 CONVERT_DOUBLE_CHECKED(number, args[0]);
5786
5787 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5788 if (number > 0 && number <= Smi::kMaxValue) {
5789 return Smi::FromInt(static_cast<int>(number));
5790 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005791 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005792}
5793
5794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005795RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005796 NoHandleAllocation ha;
5797 ASSERT(args.length() == 1);
5798
5799 CONVERT_DOUBLE_CHECKED(number, args[0]);
5800
5801 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5802 if (number > 0 && number <= Smi::kMaxValue) {
5803 return Smi::FromInt(static_cast<int>(number));
5804 }
5805
5806 double double_value = DoubleToInteger(number);
5807 // Map both -0 and +0 to +0.
5808 if (double_value == 0) double_value = 0;
5809
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005810 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005811}
5812
5813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005814RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005815 NoHandleAllocation ha;
5816 ASSERT(args.length() == 1);
5817
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005818 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005819 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005820}
5821
5822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005823RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005824 NoHandleAllocation ha;
5825 ASSERT(args.length() == 1);
5826
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005827 CONVERT_DOUBLE_CHECKED(number, args[0]);
5828
5829 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5830 if (number > 0 && number <= Smi::kMaxValue) {
5831 return Smi::FromInt(static_cast<int>(number));
5832 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005833 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005834}
5835
5836
ager@chromium.org870a0b62008-11-04 11:43:05 +00005837// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5838// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005839RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005840 NoHandleAllocation ha;
5841 ASSERT(args.length() == 1);
5842
5843 Object* obj = args[0];
5844 if (obj->IsSmi()) {
5845 return obj;
5846 }
5847 if (obj->IsHeapNumber()) {
5848 double value = HeapNumber::cast(obj)->value();
5849 int int_value = FastD2I(value);
5850 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5851 return Smi::FromInt(int_value);
5852 }
5853 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005854 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005855}
5856
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005857
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005858RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005859 NoHandleAllocation ha;
5860 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005861 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005862}
5863
5864
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005865RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005866 NoHandleAllocation ha;
5867 ASSERT(args.length() == 2);
5868
5869 CONVERT_DOUBLE_CHECKED(x, args[0]);
5870 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005871 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005872}
5873
5874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005875RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005876 NoHandleAllocation ha;
5877 ASSERT(args.length() == 2);
5878
5879 CONVERT_DOUBLE_CHECKED(x, args[0]);
5880 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005881 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005882}
5883
5884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005885RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005886 NoHandleAllocation ha;
5887 ASSERT(args.length() == 2);
5888
5889 CONVERT_DOUBLE_CHECKED(x, args[0]);
5890 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005891 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005892}
5893
5894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005895RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005896 NoHandleAllocation ha;
5897 ASSERT(args.length() == 1);
5898
5899 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005900 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005901}
5902
5903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005904RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005905 NoHandleAllocation ha;
5906 ASSERT(args.length() == 0);
5907
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005908 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005909}
5910
5911
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005912RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005913 NoHandleAllocation ha;
5914 ASSERT(args.length() == 2);
5915
5916 CONVERT_DOUBLE_CHECKED(x, args[0]);
5917 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005918 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005919}
5920
5921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005922RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005923 NoHandleAllocation ha;
5924 ASSERT(args.length() == 2);
5925
5926 CONVERT_DOUBLE_CHECKED(x, args[0]);
5927 CONVERT_DOUBLE_CHECKED(y, args[1]);
5928
ager@chromium.org3811b432009-10-28 14:53:37 +00005929 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005930 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005931 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005932}
5933
5934
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005935RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005936 NoHandleAllocation ha;
5937 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005938 CONVERT_CHECKED(String, str1, args[0]);
5939 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005940 isolate->counters()->string_add_runtime()->Increment();
5941 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005942}
5943
5944
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005945template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005946static inline void StringBuilderConcatHelper(String* special,
5947 sinkchar* sink,
5948 FixedArray* fixed_array,
5949 int array_length) {
5950 int position = 0;
5951 for (int i = 0; i < array_length; i++) {
5952 Object* element = fixed_array->get(i);
5953 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005954 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005955 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005956 int pos;
5957 int len;
5958 if (encoded_slice > 0) {
5959 // Position and length encoded in one smi.
5960 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5961 len = StringBuilderSubstringLength::decode(encoded_slice);
5962 } else {
5963 // Position and length encoded in two smis.
5964 Object* obj = fixed_array->get(++i);
5965 ASSERT(obj->IsSmi());
5966 pos = Smi::cast(obj)->value();
5967 len = -encoded_slice;
5968 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005969 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005970 sink + position,
5971 pos,
5972 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005973 position += len;
5974 } else {
5975 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005976 int element_length = string->length();
5977 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005978 position += element_length;
5979 }
5980 }
5981}
5982
5983
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005984RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005985 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005986 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005987 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005988 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005989 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005990 return Failure::OutOfMemoryException();
5991 }
5992 int array_length = Smi::cast(args[1])->value();
5993 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005994
5995 // This assumption is used by the slice encoding in one or two smis.
5996 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5997
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005998 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005999 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006000 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001 }
6002 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006003 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006004 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006005 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006006
6007 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006008 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006009 } else if (array_length == 1) {
6010 Object* first = fixed_array->get(0);
6011 if (first->IsString()) return first;
6012 }
6013
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006014 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006015 int position = 0;
6016 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006017 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006018 Object* elt = fixed_array->get(i);
6019 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006020 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006021 int smi_value = Smi::cast(elt)->value();
6022 int pos;
6023 int len;
6024 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006025 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006026 pos = StringBuilderSubstringPosition::decode(smi_value);
6027 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006028 } else {
6029 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006030 len = -smi_value;
6031 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006032 i++;
6033 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006034 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006035 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006036 Object* next_smi = fixed_array->get(i);
6037 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006038 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006039 }
6040 pos = Smi::cast(next_smi)->value();
6041 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006042 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006043 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006044 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006045 ASSERT(pos >= 0);
6046 ASSERT(len >= 0);
6047 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006048 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006049 }
6050 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006051 } else if (elt->IsString()) {
6052 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006053 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006054 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006055 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006056 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006057 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006058 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006059 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006061 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006062 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006063 return Failure::OutOfMemoryException();
6064 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006065 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006066 }
6067
6068 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006069 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006070
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006071 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006072 { MaybeObject* maybe_object =
6073 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006074 if (!maybe_object->ToObject(&object)) return maybe_object;
6075 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006076 SeqAsciiString* answer = SeqAsciiString::cast(object);
6077 StringBuilderConcatHelper(special,
6078 answer->GetChars(),
6079 fixed_array,
6080 array_length);
6081 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006082 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006083 { MaybeObject* maybe_object =
6084 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006085 if (!maybe_object->ToObject(&object)) return maybe_object;
6086 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006087 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6088 StringBuilderConcatHelper(special,
6089 answer->GetChars(),
6090 fixed_array,
6091 array_length);
6092 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006093 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006094}
6095
6096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006097RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006098 NoHandleAllocation ha;
6099 ASSERT(args.length() == 3);
6100 CONVERT_CHECKED(JSArray, array, args[0]);
6101 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006102 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006103 return Failure::OutOfMemoryException();
6104 }
6105 int array_length = Smi::cast(args[1])->value();
6106 CONVERT_CHECKED(String, separator, args[2]);
6107
6108 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006109 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006110 }
6111 FixedArray* fixed_array = FixedArray::cast(array->elements());
6112 if (fixed_array->length() < array_length) {
6113 array_length = fixed_array->length();
6114 }
6115
6116 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006117 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006118 } else if (array_length == 1) {
6119 Object* first = fixed_array->get(0);
6120 if (first->IsString()) return first;
6121 }
6122
6123 int separator_length = separator->length();
6124 int max_nof_separators =
6125 (String::kMaxLength + separator_length - 1) / separator_length;
6126 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006127 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006128 return Failure::OutOfMemoryException();
6129 }
6130 int length = (array_length - 1) * separator_length;
6131 for (int i = 0; i < array_length; i++) {
6132 Object* element_obj = fixed_array->get(i);
6133 if (!element_obj->IsString()) {
6134 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006135 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006136 }
6137 String* element = String::cast(element_obj);
6138 int increment = element->length();
6139 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006140 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006141 return Failure::OutOfMemoryException();
6142 }
6143 length += increment;
6144 }
6145
6146 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006147 { MaybeObject* maybe_object =
6148 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006149 if (!maybe_object->ToObject(&object)) return maybe_object;
6150 }
6151 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6152
6153 uc16* sink = answer->GetChars();
6154#ifdef DEBUG
6155 uc16* end = sink + length;
6156#endif
6157
6158 String* first = String::cast(fixed_array->get(0));
6159 int first_length = first->length();
6160 String::WriteToFlat(first, sink, 0, first_length);
6161 sink += first_length;
6162
6163 for (int i = 1; i < array_length; i++) {
6164 ASSERT(sink + separator_length <= end);
6165 String::WriteToFlat(separator, sink, 0, separator_length);
6166 sink += separator_length;
6167
6168 String* element = String::cast(fixed_array->get(i));
6169 int element_length = element->length();
6170 ASSERT(sink + element_length <= end);
6171 String::WriteToFlat(element, sink, 0, element_length);
6172 sink += element_length;
6173 }
6174 ASSERT(sink == end);
6175
6176 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6177 return answer;
6178}
6179
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006180template <typename Char>
6181static void JoinSparseArrayWithSeparator(FixedArray* elements,
6182 int elements_length,
6183 uint32_t array_length,
6184 String* separator,
6185 Vector<Char> buffer) {
6186 int previous_separator_position = 0;
6187 int separator_length = separator->length();
6188 int cursor = 0;
6189 for (int i = 0; i < elements_length; i += 2) {
6190 int position = NumberToInt32(elements->get(i));
6191 String* string = String::cast(elements->get(i + 1));
6192 int string_length = string->length();
6193 if (string->length() > 0) {
6194 while (previous_separator_position < position) {
6195 String::WriteToFlat<Char>(separator, &buffer[cursor],
6196 0, separator_length);
6197 cursor += separator_length;
6198 previous_separator_position++;
6199 }
6200 String::WriteToFlat<Char>(string, &buffer[cursor],
6201 0, string_length);
6202 cursor += string->length();
6203 }
6204 }
6205 if (separator_length > 0) {
6206 // Array length must be representable as a signed 32-bit number,
6207 // otherwise the total string length would have been too large.
6208 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6209 int last_array_index = static_cast<int>(array_length - 1);
6210 while (previous_separator_position < last_array_index) {
6211 String::WriteToFlat<Char>(separator, &buffer[cursor],
6212 0, separator_length);
6213 cursor += separator_length;
6214 previous_separator_position++;
6215 }
6216 }
6217 ASSERT(cursor <= buffer.length());
6218}
6219
6220
6221RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6222 NoHandleAllocation ha;
6223 ASSERT(args.length() == 3);
6224 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6225 RUNTIME_ASSERT(elements_array->HasFastElements());
6226 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6227 CONVERT_CHECKED(String, separator, args[2]);
6228 // elements_array is fast-mode JSarray of alternating positions
6229 // (increasing order) and strings.
6230 // array_length is length of original array (used to add separators);
6231 // separator is string to put between elements. Assumed to be non-empty.
6232
6233 // Find total length of join result.
6234 int string_length = 0;
6235 bool is_ascii = true;
6236 int max_string_length = SeqAsciiString::kMaxLength;
6237 bool overflow = false;
6238 CONVERT_NUMBER_CHECKED(int, elements_length,
6239 Int32, elements_array->length());
6240 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6241 FixedArray* elements = FixedArray::cast(elements_array->elements());
6242 for (int i = 0; i < elements_length; i += 2) {
6243 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6244 CONVERT_CHECKED(String, string, elements->get(i + 1));
6245 int length = string->length();
6246 if (is_ascii && !string->IsAsciiRepresentation()) {
6247 is_ascii = false;
6248 max_string_length = SeqTwoByteString::kMaxLength;
6249 }
6250 if (length > max_string_length ||
6251 max_string_length - length < string_length) {
6252 overflow = true;
6253 break;
6254 }
6255 string_length += length;
6256 }
6257 int separator_length = separator->length();
6258 if (!overflow && separator_length > 0) {
6259 if (array_length <= 0x7fffffffu) {
6260 int separator_count = static_cast<int>(array_length) - 1;
6261 int remaining_length = max_string_length - string_length;
6262 if ((remaining_length / separator_length) >= separator_count) {
6263 string_length += separator_length * (array_length - 1);
6264 } else {
6265 // Not room for the separators within the maximal string length.
6266 overflow = true;
6267 }
6268 } else {
6269 // Nonempty separator and at least 2^31-1 separators necessary
6270 // means that the string is too large to create.
6271 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6272 overflow = true;
6273 }
6274 }
6275 if (overflow) {
6276 // Throw OutOfMemory exception for creating too large a string.
6277 V8::FatalProcessOutOfMemory("Array join result too large.");
6278 }
6279
6280 if (is_ascii) {
6281 MaybeObject* result_allocation =
6282 isolate->heap()->AllocateRawAsciiString(string_length);
6283 if (result_allocation->IsFailure()) return result_allocation;
6284 SeqAsciiString* result_string =
6285 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6286 JoinSparseArrayWithSeparator<char>(elements,
6287 elements_length,
6288 array_length,
6289 separator,
6290 Vector<char>(result_string->GetChars(),
6291 string_length));
6292 return result_string;
6293 } else {
6294 MaybeObject* result_allocation =
6295 isolate->heap()->AllocateRawTwoByteString(string_length);
6296 if (result_allocation->IsFailure()) return result_allocation;
6297 SeqTwoByteString* result_string =
6298 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6299 JoinSparseArrayWithSeparator<uc16>(elements,
6300 elements_length,
6301 array_length,
6302 separator,
6303 Vector<uc16>(result_string->GetChars(),
6304 string_length));
6305 return result_string;
6306 }
6307}
6308
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006309
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006310RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006311 NoHandleAllocation ha;
6312 ASSERT(args.length() == 2);
6313
6314 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6315 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006316 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006317}
6318
6319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006320RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006321 NoHandleAllocation ha;
6322 ASSERT(args.length() == 2);
6323
6324 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6325 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006326 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006327}
6328
6329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006330RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006331 NoHandleAllocation ha;
6332 ASSERT(args.length() == 2);
6333
6334 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6335 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006336 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006337}
6338
6339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006340RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006341 NoHandleAllocation ha;
6342 ASSERT(args.length() == 1);
6343
6344 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006345 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006346}
6347
6348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006349RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006350 NoHandleAllocation ha;
6351 ASSERT(args.length() == 2);
6352
6353 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6354 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006355 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006356}
6357
6358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006359RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006360 NoHandleAllocation ha;
6361 ASSERT(args.length() == 2);
6362
6363 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6364 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006365 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006366}
6367
6368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006369RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006370 NoHandleAllocation ha;
6371 ASSERT(args.length() == 2);
6372
6373 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6374 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006375 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006376}
6377
6378
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006379RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006380 NoHandleAllocation ha;
6381 ASSERT(args.length() == 2);
6382
6383 CONVERT_DOUBLE_CHECKED(x, args[0]);
6384 CONVERT_DOUBLE_CHECKED(y, args[1]);
6385 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6386 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6387 if (x == y) return Smi::FromInt(EQUAL);
6388 Object* result;
6389 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6390 result = Smi::FromInt(EQUAL);
6391 } else {
6392 result = Smi::FromInt(NOT_EQUAL);
6393 }
6394 return result;
6395}
6396
6397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006398RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006399 NoHandleAllocation ha;
6400 ASSERT(args.length() == 2);
6401
6402 CONVERT_CHECKED(String, x, args[0]);
6403 CONVERT_CHECKED(String, y, args[1]);
6404
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006405 bool not_equal = !x->Equals(y);
6406 // This is slightly convoluted because the value that signifies
6407 // equality is 0 and inequality is 1 so we have to negate the result
6408 // from String::Equals.
6409 ASSERT(not_equal == 0 || not_equal == 1);
6410 STATIC_CHECK(EQUAL == 0);
6411 STATIC_CHECK(NOT_EQUAL == 1);
6412 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006413}
6414
6415
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006416RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006417 NoHandleAllocation ha;
6418 ASSERT(args.length() == 3);
6419
6420 CONVERT_DOUBLE_CHECKED(x, args[0]);
6421 CONVERT_DOUBLE_CHECKED(y, args[1]);
6422 if (isnan(x) || isnan(y)) return args[2];
6423 if (x == y) return Smi::FromInt(EQUAL);
6424 if (isless(x, y)) return Smi::FromInt(LESS);
6425 return Smi::FromInt(GREATER);
6426}
6427
6428
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006429// Compare two Smis as if they were converted to strings and then
6430// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006431RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006432 NoHandleAllocation ha;
6433 ASSERT(args.length() == 2);
6434
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006435 // Extract the integer values from the Smis.
6436 CONVERT_CHECKED(Smi, x, args[0]);
6437 CONVERT_CHECKED(Smi, y, args[1]);
6438 int x_value = x->value();
6439 int y_value = y->value();
6440
6441 // If the integers are equal so are the string representations.
6442 if (x_value == y_value) return Smi::FromInt(EQUAL);
6443
6444 // If one of the integers are zero the normal integer order is the
6445 // same as the lexicographic order of the string representations.
6446 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6447
ager@chromium.org32912102009-01-16 10:38:43 +00006448 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006449 // smallest because the char code of '-' is less than the char code
6450 // of any digit. Otherwise, we make both values positive.
6451 if (x_value < 0 || y_value < 0) {
6452 if (y_value >= 0) return Smi::FromInt(LESS);
6453 if (x_value >= 0) return Smi::FromInt(GREATER);
6454 x_value = -x_value;
6455 y_value = -y_value;
6456 }
6457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006458 // Arrays for the individual characters of the two Smis. Smis are
6459 // 31 bit integers and 10 decimal digits are therefore enough.
6460 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6461 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6462 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6463
6464
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006465 // Convert the integers to arrays of their decimal digits.
6466 int x_index = 0;
6467 int y_index = 0;
6468 while (x_value > 0) {
6469 x_elms[x_index++] = x_value % 10;
6470 x_value /= 10;
6471 }
6472 while (y_value > 0) {
6473 y_elms[y_index++] = y_value % 10;
6474 y_value /= 10;
6475 }
6476
6477 // Loop through the arrays of decimal digits finding the first place
6478 // where they differ.
6479 while (--x_index >= 0 && --y_index >= 0) {
6480 int diff = x_elms[x_index] - y_elms[y_index];
6481 if (diff != 0) return Smi::FromInt(diff);
6482 }
6483
6484 // If one array is a suffix of the other array, the longest array is
6485 // the representation of the largest of the Smis in the
6486 // lexicographic ordering.
6487 return Smi::FromInt(x_index - y_index);
6488}
6489
6490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006491static Object* StringInputBufferCompare(RuntimeState* state,
6492 String* x,
6493 String* y) {
6494 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6495 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006496 bufx.Reset(x);
6497 bufy.Reset(y);
6498 while (bufx.has_more() && bufy.has_more()) {
6499 int d = bufx.GetNext() - bufy.GetNext();
6500 if (d < 0) return Smi::FromInt(LESS);
6501 else if (d > 0) return Smi::FromInt(GREATER);
6502 }
6503
6504 // x is (non-trivial) prefix of y:
6505 if (bufy.has_more()) return Smi::FromInt(LESS);
6506 // y is prefix of x:
6507 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6508}
6509
6510
6511static Object* FlatStringCompare(String* x, String* y) {
6512 ASSERT(x->IsFlat());
6513 ASSERT(y->IsFlat());
6514 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6515 int prefix_length = x->length();
6516 if (y->length() < prefix_length) {
6517 prefix_length = y->length();
6518 equal_prefix_result = Smi::FromInt(GREATER);
6519 } else if (y->length() > prefix_length) {
6520 equal_prefix_result = Smi::FromInt(LESS);
6521 }
6522 int r;
6523 if (x->IsAsciiRepresentation()) {
6524 Vector<const char> x_chars = x->ToAsciiVector();
6525 if (y->IsAsciiRepresentation()) {
6526 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006527 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006528 } else {
6529 Vector<const uc16> y_chars = y->ToUC16Vector();
6530 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6531 }
6532 } else {
6533 Vector<const uc16> x_chars = x->ToUC16Vector();
6534 if (y->IsAsciiRepresentation()) {
6535 Vector<const char> y_chars = y->ToAsciiVector();
6536 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6537 } else {
6538 Vector<const uc16> y_chars = y->ToUC16Vector();
6539 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6540 }
6541 }
6542 Object* result;
6543 if (r == 0) {
6544 result = equal_prefix_result;
6545 } else {
6546 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6547 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006548 ASSERT(result ==
6549 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006550 return result;
6551}
6552
6553
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006554RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006555 NoHandleAllocation ha;
6556 ASSERT(args.length() == 2);
6557
6558 CONVERT_CHECKED(String, x, args[0]);
6559 CONVERT_CHECKED(String, y, args[1]);
6560
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006561 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006562
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006563 // A few fast case tests before we flatten.
6564 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006565 if (y->length() == 0) {
6566 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006567 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006568 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569 return Smi::FromInt(LESS);
6570 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006571
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006572 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006573 if (d < 0) return Smi::FromInt(LESS);
6574 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575
lrn@chromium.org303ada72010-10-27 09:33:13 +00006576 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006577 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006578 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6579 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006580 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006581 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6582 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006584 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006585 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006586}
6587
6588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006589RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006590 NoHandleAllocation ha;
6591 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006592 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593
6594 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006595 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006596}
6597
6598
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006599RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006600 NoHandleAllocation ha;
6601 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006602 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006603
6604 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006605 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006606}
6607
6608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006609RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610 NoHandleAllocation ha;
6611 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006612 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006613
6614 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006615 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006616}
6617
6618
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006619static const double kPiDividedBy4 = 0.78539816339744830962;
6620
6621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006622RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623 NoHandleAllocation ha;
6624 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006625 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006626
6627 CONVERT_DOUBLE_CHECKED(x, args[0]);
6628 CONVERT_DOUBLE_CHECKED(y, args[1]);
6629 double result;
6630 if (isinf(x) && isinf(y)) {
6631 // Make sure that the result in case of two infinite arguments
6632 // is a multiple of Pi / 4. The sign of the result is determined
6633 // by the first argument (x) and the sign of the second argument
6634 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006635 int multiplier = (x < 0) ? -1 : 1;
6636 if (y < 0) multiplier *= 3;
6637 result = multiplier * kPiDividedBy4;
6638 } else {
6639 result = atan2(x, y);
6640 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006641 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642}
6643
6644
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006645RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006646 NoHandleAllocation ha;
6647 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006648 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006649
6650 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006651 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652}
6653
6654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006655RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006656 NoHandleAllocation ha;
6657 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006658 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006659
6660 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006661 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006662}
6663
6664
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006665RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006666 NoHandleAllocation ha;
6667 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006668 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006669
6670 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006671 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006672}
6673
6674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006675RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006676 NoHandleAllocation ha;
6677 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006678 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679
6680 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006681 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006682}
6683
6684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006685RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006686 NoHandleAllocation ha;
6687 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006688 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006689
6690 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006691 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006692}
6693
6694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006695RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006696 NoHandleAllocation ha;
6697 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006698 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006699
6700 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006701
6702 // If the second argument is a smi, it is much faster to call the
6703 // custom powi() function than the generic pow().
6704 if (args[1]->IsSmi()) {
6705 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006706 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006707 }
6708
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006710 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006711}
6712
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006713// Fast version of Math.pow if we know that y is not an integer and
6714// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006715RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006716 NoHandleAllocation ha;
6717 ASSERT(args.length() == 2);
6718 CONVERT_DOUBLE_CHECKED(x, args[0]);
6719 CONVERT_DOUBLE_CHECKED(y, args[1]);
6720 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006721 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006722 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006723 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006724 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006725 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006726 }
6727}
6728
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006729
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006730RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006731 NoHandleAllocation ha;
6732 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006733 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006734
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006735 if (!args[0]->IsHeapNumber()) {
6736 // Must be smi. Return the argument unchanged for all the other types
6737 // to make fuzz-natives test happy.
6738 return args[0];
6739 }
6740
6741 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6742
6743 double value = number->value();
6744 int exponent = number->get_exponent();
6745 int sign = number->get_sign();
6746
danno@chromium.org160a7b02011-04-18 15:51:38 +00006747 if (exponent < -1) {
6748 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6749 if (sign) return isolate->heap()->minus_zero_value();
6750 return Smi::FromInt(0);
6751 }
6752
6753 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6754 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6755 // agument holds for 32-bit smis).
6756 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006757 return Smi::FromInt(static_cast<int>(value + 0.5));
6758 }
6759
6760 // If the magnitude is big enough, there's no place for fraction part. If we
6761 // try to add 0.5 to this number, 1.0 will be added instead.
6762 if (exponent >= 52) {
6763 return number;
6764 }
6765
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006766 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006767
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006768 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006769 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770}
6771
6772
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006773RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006774 NoHandleAllocation ha;
6775 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006776 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006777
6778 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006779 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006780}
6781
6782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006783RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006784 NoHandleAllocation ha;
6785 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006786 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006787
6788 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006789 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006790}
6791
6792
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006793RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006794 NoHandleAllocation ha;
6795 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006796 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006797
6798 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006799 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006800}
6801
6802
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006803static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006804 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6805 181, 212, 243, 273, 304, 334};
6806 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6807 182, 213, 244, 274, 305, 335};
6808
6809 year += month / 12;
6810 month %= 12;
6811 if (month < 0) {
6812 year--;
6813 month += 12;
6814 }
6815
6816 ASSERT(month >= 0);
6817 ASSERT(month < 12);
6818
6819 // year_delta is an arbitrary number such that:
6820 // a) year_delta = -1 (mod 400)
6821 // b) year + year_delta > 0 for years in the range defined by
6822 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6823 // Jan 1 1970. This is required so that we don't run into integer
6824 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006825 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006826 // operations.
6827 static const int year_delta = 399999;
6828 static const int base_day = 365 * (1970 + year_delta) +
6829 (1970 + year_delta) / 4 -
6830 (1970 + year_delta) / 100 +
6831 (1970 + year_delta) / 400;
6832
6833 int year1 = year + year_delta;
6834 int day_from_year = 365 * year1 +
6835 year1 / 4 -
6836 year1 / 100 +
6837 year1 / 400 -
6838 base_day;
6839
6840 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006841 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006842 }
6843
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006844 return day_from_year + day_from_month_leap[month] + day - 1;
6845}
6846
6847
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006848RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006849 NoHandleAllocation ha;
6850 ASSERT(args.length() == 3);
6851
6852 CONVERT_SMI_CHECKED(year, args[0]);
6853 CONVERT_SMI_CHECKED(month, args[1]);
6854 CONVERT_SMI_CHECKED(date, args[2]);
6855
6856 return Smi::FromInt(MakeDay(year, month, date));
6857}
6858
6859
6860static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6861static const int kDaysIn4Years = 4 * 365 + 1;
6862static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6863static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6864static const int kDays1970to2000 = 30 * 365 + 7;
6865static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6866 kDays1970to2000;
6867static const int kYearsOffset = 400000;
6868
6869static const char kDayInYear[] = {
6870 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6871 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6872 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6873 22, 23, 24, 25, 26, 27, 28,
6874 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6875 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6876 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6877 22, 23, 24, 25, 26, 27, 28, 29, 30,
6878 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6879 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6880 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6881 22, 23, 24, 25, 26, 27, 28, 29, 30,
6882 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6883 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6884 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6885 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6886 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6887 22, 23, 24, 25, 26, 27, 28, 29, 30,
6888 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6889 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6890 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6891 22, 23, 24, 25, 26, 27, 28, 29, 30,
6892 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6893 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6894
6895 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6896 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6897 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6898 22, 23, 24, 25, 26, 27, 28,
6899 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6900 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6901 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6902 22, 23, 24, 25, 26, 27, 28, 29, 30,
6903 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6904 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6905 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6906 22, 23, 24, 25, 26, 27, 28, 29, 30,
6907 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6908 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6909 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6910 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6911 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6912 22, 23, 24, 25, 26, 27, 28, 29, 30,
6913 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6914 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6915 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6916 22, 23, 24, 25, 26, 27, 28, 29, 30,
6917 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6918 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6919
6920 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6921 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6922 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6923 22, 23, 24, 25, 26, 27, 28, 29,
6924 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6925 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6926 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6927 22, 23, 24, 25, 26, 27, 28, 29, 30,
6928 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6929 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6930 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6931 22, 23, 24, 25, 26, 27, 28, 29, 30,
6932 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6933 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6934 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6935 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6936 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6937 22, 23, 24, 25, 26, 27, 28, 29, 30,
6938 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6939 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6940 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6941 22, 23, 24, 25, 26, 27, 28, 29, 30,
6942 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6943 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6944
6945 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6946 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6947 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6948 22, 23, 24, 25, 26, 27, 28,
6949 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6950 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6951 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6952 22, 23, 24, 25, 26, 27, 28, 29, 30,
6953 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6954 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6955 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6956 22, 23, 24, 25, 26, 27, 28, 29, 30,
6957 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6958 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6959 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6960 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6961 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6962 22, 23, 24, 25, 26, 27, 28, 29, 30,
6963 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6964 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6965 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6966 22, 23, 24, 25, 26, 27, 28, 29, 30,
6967 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6968 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6969
6970static const char kMonthInYear[] = {
6971 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,
6972 0, 0, 0, 0, 0, 0,
6973 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,
6974 1, 1, 1,
6975 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,
6976 2, 2, 2, 2, 2, 2,
6977 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,
6978 3, 3, 3, 3, 3,
6979 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,
6980 4, 4, 4, 4, 4, 4,
6981 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,
6982 5, 5, 5, 5, 5,
6983 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,
6984 6, 6, 6, 6, 6, 6,
6985 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,
6986 7, 7, 7, 7, 7, 7,
6987 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,
6988 8, 8, 8, 8, 8,
6989 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,
6990 9, 9, 9, 9, 9, 9,
6991 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6992 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6993 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6994 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6995
6996 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,
6997 0, 0, 0, 0, 0, 0,
6998 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,
6999 1, 1, 1,
7000 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,
7001 2, 2, 2, 2, 2, 2,
7002 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,
7003 3, 3, 3, 3, 3,
7004 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,
7005 4, 4, 4, 4, 4, 4,
7006 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,
7007 5, 5, 5, 5, 5,
7008 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,
7009 6, 6, 6, 6, 6, 6,
7010 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,
7011 7, 7, 7, 7, 7, 7,
7012 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,
7013 8, 8, 8, 8, 8,
7014 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,
7015 9, 9, 9, 9, 9, 9,
7016 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7017 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7018 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7019 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7020
7021 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,
7022 0, 0, 0, 0, 0, 0,
7023 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,
7024 1, 1, 1, 1,
7025 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,
7026 2, 2, 2, 2, 2, 2,
7027 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,
7028 3, 3, 3, 3, 3,
7029 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,
7030 4, 4, 4, 4, 4, 4,
7031 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,
7032 5, 5, 5, 5, 5,
7033 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,
7034 6, 6, 6, 6, 6, 6,
7035 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,
7036 7, 7, 7, 7, 7, 7,
7037 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,
7038 8, 8, 8, 8, 8,
7039 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,
7040 9, 9, 9, 9, 9, 9,
7041 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7042 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7043 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7044 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7045
7046 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,
7047 0, 0, 0, 0, 0, 0,
7048 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,
7049 1, 1, 1,
7050 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,
7051 2, 2, 2, 2, 2, 2,
7052 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,
7053 3, 3, 3, 3, 3,
7054 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,
7055 4, 4, 4, 4, 4, 4,
7056 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,
7057 5, 5, 5, 5, 5,
7058 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,
7059 6, 6, 6, 6, 6, 6,
7060 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,
7061 7, 7, 7, 7, 7, 7,
7062 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,
7063 8, 8, 8, 8, 8,
7064 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,
7065 9, 9, 9, 9, 9, 9,
7066 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7067 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7068 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7069 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7070
7071
7072// This function works for dates from 1970 to 2099.
7073static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007074 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007075#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007076 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007077#endif
7078
7079 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7080 date %= kDaysIn4Years;
7081
7082 month = kMonthInYear[date];
7083 day = kDayInYear[date];
7084
7085 ASSERT(MakeDay(year, month, day) == save_date);
7086}
7087
7088
7089static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007090 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007091#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007092 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007093#endif
7094
7095 date += kDaysOffset;
7096 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7097 date %= kDaysIn400Years;
7098
7099 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7100
7101 date--;
7102 int yd1 = date / kDaysIn100Years;
7103 date %= kDaysIn100Years;
7104 year += 100 * yd1;
7105
7106 date++;
7107 int yd2 = date / kDaysIn4Years;
7108 date %= kDaysIn4Years;
7109 year += 4 * yd2;
7110
7111 date--;
7112 int yd3 = date / 365;
7113 date %= 365;
7114 year += yd3;
7115
7116 bool is_leap = (!yd1 || yd2) && !yd3;
7117
7118 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007119 ASSERT(is_leap || (date >= 0));
7120 ASSERT((date < 365) || (is_leap && (date < 366)));
7121 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7122 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7123 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007124
7125 if (is_leap) {
7126 day = kDayInYear[2*365 + 1 + date];
7127 month = kMonthInYear[2*365 + 1 + date];
7128 } else {
7129 day = kDayInYear[date];
7130 month = kMonthInYear[date];
7131 }
7132
7133 ASSERT(MakeDay(year, month, day) == save_date);
7134}
7135
7136
7137static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007138 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007139 if (date >= 0 && date < 32 * kDaysIn4Years) {
7140 DateYMDFromTimeAfter1970(date, year, month, day);
7141 } else {
7142 DateYMDFromTimeSlow(date, year, month, day);
7143 }
7144}
7145
7146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007147RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007148 NoHandleAllocation ha;
7149 ASSERT(args.length() == 2);
7150
7151 CONVERT_DOUBLE_CHECKED(t, args[0]);
7152 CONVERT_CHECKED(JSArray, res_array, args[1]);
7153
7154 int year, month, day;
7155 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7156
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007157 RUNTIME_ASSERT(res_array->elements()->map() ==
7158 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007159 FixedArray* elms = FixedArray::cast(res_array->elements());
7160 RUNTIME_ASSERT(elms->length() == 3);
7161
7162 elms->set(0, Smi::FromInt(year));
7163 elms->set(1, Smi::FromInt(month));
7164 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007165
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007166 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007167}
7168
7169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007170RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007171 NoHandleAllocation ha;
7172 ASSERT(args.length() == 3);
7173
7174 JSFunction* callee = JSFunction::cast(args[0]);
7175 Object** parameters = reinterpret_cast<Object**>(args[1]);
7176 const int length = Smi::cast(args[2])->value();
7177
lrn@chromium.org303ada72010-10-27 09:33:13 +00007178 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007179 { MaybeObject* maybe_result =
7180 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007181 if (!maybe_result->ToObject(&result)) return maybe_result;
7182 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007183 // Allocate the elements if needed.
7184 if (length > 0) {
7185 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007186 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007187 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007188 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7189 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007190
7191 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007192 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007193 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007194 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007195
7196 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007197 for (int i = 0; i < length; i++) {
7198 array->set(i, *--parameters, mode);
7199 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007200 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007201 }
7202 return result;
7203}
7204
7205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007206RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007207 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007208 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007209 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007210 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007211 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007212
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007213 // Allocate global closures in old space and allocate local closures
7214 // in new space. Additionally pretenure closures that are assigned
7215 // directly to properties.
7216 pretenure = pretenure || (context->global_context() == *context);
7217 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007218 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007219 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7220 context,
7221 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007222 return *result;
7223}
7224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007225
7226static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7227 int* total_argc) {
7228 // Find frame containing arguments passed to the caller.
7229 JavaScriptFrameIterator it;
7230 JavaScriptFrame* frame = it.frame();
7231 List<JSFunction*> functions(2);
7232 frame->GetFunctions(&functions);
7233 if (functions.length() > 1) {
7234 int inlined_frame_index = functions.length() - 1;
7235 JSFunction* inlined_function = functions[inlined_frame_index];
7236 int args_count = inlined_function->shared()->formal_parameter_count();
7237 ScopedVector<SlotRef> args_slots(args_count);
7238 SlotRef::ComputeSlotMappingForArguments(frame,
7239 inlined_frame_index,
7240 &args_slots);
7241
7242 *total_argc = bound_argc + args_count;
7243 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7244 for (int i = 0; i < args_count; i++) {
7245 Handle<Object> val = args_slots[i].GetValue();
7246 param_data[bound_argc + i] = val.location();
7247 }
7248 return param_data;
7249 } else {
7250 it.AdvanceToArgumentsFrame();
7251 frame = it.frame();
7252 int args_count = frame->ComputeParametersCount();
7253
7254 *total_argc = bound_argc + args_count;
7255 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7256 for (int i = 0; i < args_count; i++) {
7257 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7258 param_data[bound_argc + i] = val.location();
7259 }
7260 return param_data;
7261 }
7262}
7263
7264
7265RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007266 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007267 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007268 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007269 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007270
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007271 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007272 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007273 int bound_argc = 0;
7274 if (!args[1]->IsNull()) {
7275 CONVERT_ARG_CHECKED(JSArray, params, 1);
7276 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007277 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007278 bound_argc = Smi::cast(params->length())->value();
7279 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007281 int total_argc = 0;
7282 SmartPointer<Object**> param_data =
7283 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007284 for (int i = 0; i < bound_argc; i++) {
7285 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007286 param_data[i] = val.location();
7287 }
7288
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007289 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007290 Handle<Object> result =
7291 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007292 if (exception) {
7293 return Failure::Exception();
7294 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007295
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007296 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007297 return *result;
7298}
7299
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007300
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007301static void TrySettingInlineConstructStub(Isolate* isolate,
7302 Handle<JSFunction> function) {
7303 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007304 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007305 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007306 }
7307 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007308 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007309 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007310 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007311 function->shared()->set_construct_stub(
7312 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007313 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007314 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007315}
7316
7317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007318RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007319 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007320 ASSERT(args.length() == 1);
7321
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007322 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007323
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007324 // If the constructor isn't a proper function we throw a type error.
7325 if (!constructor->IsJSFunction()) {
7326 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7327 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007328 isolate->factory()->NewTypeError("not_constructor", arguments);
7329 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007330 }
7331
7332 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007333
7334 // If function should not have prototype, construction is not allowed. In this
7335 // case generated code bailouts here, since function has no initial_map.
7336 if (!function->should_have_prototype()) {
7337 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7338 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007339 isolate->factory()->NewTypeError("not_constructor", arguments);
7340 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007341 }
7342
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007343#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007344 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007345 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007346 if (debug->StepInActive()) {
7347 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007348 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007349#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007350
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007351 if (function->has_initial_map()) {
7352 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007353 // The 'Function' function ignores the receiver object when
7354 // called using 'new' and creates a new JSFunction object that
7355 // is returned. The receiver object is only used for error
7356 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007357 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007358 // allocate JSFunctions since it does not properly initialize
7359 // the shared part of the function. Since the receiver is
7360 // ignored anyway, we use the global object as the receiver
7361 // instead of a new JSFunction object. This way, errors are
7362 // reported the same way whether or not 'Function' is called
7363 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007364 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007365 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007366 }
7367
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007368 // The function should be compiled for the optimization hints to be
7369 // available. We cannot use EnsureCompiled because that forces a
7370 // compilation through the shared function info which makes it
7371 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007372 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007373 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007374
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007375 if (!function->has_initial_map() &&
7376 shared->IsInobjectSlackTrackingInProgress()) {
7377 // The tracking is already in progress for another function. We can only
7378 // track one initial_map at a time, so we force the completion before the
7379 // function is called as a constructor for the first time.
7380 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007381 }
7382
7383 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007384 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7385 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007386 // Delay setting the stub if inobject slack tracking is in progress.
7387 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007388 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007389 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007390
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007391 isolate->counters()->constructed_objects()->Increment();
7392 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007393
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007394 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395}
7396
7397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007398RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007400 ASSERT(args.length() == 1);
7401
7402 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7403 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007404 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007405
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007406 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007407}
7408
7409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007410RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007411 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007412 ASSERT(args.length() == 1);
7413
7414 Handle<JSFunction> function = args.at<JSFunction>(0);
7415#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007416 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007417 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007418 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007419 PrintF("]\n");
7420 }
7421#endif
7422
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007423 // Compile the target function. Here we compile using CompileLazyInLoop in
7424 // order to get the optimized version. This helps code like delta-blue
7425 // that calls performance-critical routines through constructors. A
7426 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7427 // direct call. Since the in-loop tracking takes place through CallICs
7428 // this means that things called through constructors are never known to
7429 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007430 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007431 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007432 return Failure::Exception();
7433 }
7434
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007435 // All done. Return the compiled code.
7436 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007437 return function->code();
7438}
7439
7440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007441RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007442 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007443 ASSERT(args.length() == 1);
7444 Handle<JSFunction> function = args.at<JSFunction>(0);
7445 // If the function is not optimizable or debugger is active continue using the
7446 // code from the full compiler.
7447 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007448 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007449 if (FLAG_trace_opt) {
7450 PrintF("[failed to optimize ");
7451 function->PrintName();
7452 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7453 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007454 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007455 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007456 function->ReplaceCode(function->shared()->code());
7457 return function->code();
7458 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007459 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007460 return function->code();
7461 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007462 if (FLAG_trace_opt) {
7463 PrintF("[failed to optimize ");
7464 function->PrintName();
7465 PrintF(": optimized compilation failed]\n");
7466 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007467 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007468 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007469}
7470
7471
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007472RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007473 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007474 ASSERT(args.length() == 1);
7475 RUNTIME_ASSERT(args[0]->IsSmi());
7476 Deoptimizer::BailoutType type =
7477 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007478 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7479 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007480 int frames = deoptimizer->output_count();
7481
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007482 deoptimizer->MaterializeHeapNumbers();
7483 delete deoptimizer;
7484
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007485 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007486 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007487 for (int i = 0; i < frames - 1; i++) it.Advance();
7488 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007489
7490 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007491 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007492 Handle<Object> arguments;
7493 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007494 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007495 if (arguments.is_null()) {
7496 // FunctionGetArguments can't throw an exception, so cast away the
7497 // doubt with an assert.
7498 arguments = Handle<Object>(
7499 Accessors::FunctionGetArguments(*function,
7500 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007501 ASSERT(*arguments != isolate->heap()->null_value());
7502 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007503 }
7504 frame->SetExpression(i, *arguments);
7505 }
7506 }
7507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007508 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007509 if (type == Deoptimizer::EAGER) {
7510 RUNTIME_ASSERT(function->IsOptimized());
7511 } else {
7512 RUNTIME_ASSERT(!function->IsOptimized());
7513 }
7514
7515 // Avoid doing too much work when running with --always-opt and keep
7516 // the optimized code around.
7517 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007518 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007519 }
7520
7521 // Count the number of optimized activations of the function.
7522 int activations = 0;
7523 while (!it.done()) {
7524 JavaScriptFrame* frame = it.frame();
7525 if (frame->is_optimized() && frame->function() == *function) {
7526 activations++;
7527 }
7528 it.Advance();
7529 }
7530
7531 // TODO(kasperl): For now, we cannot support removing the optimized
7532 // code when we have recursive invocations of the same function.
7533 if (activations == 0) {
7534 if (FLAG_trace_deopt) {
7535 PrintF("[removing optimized code for: ");
7536 function->PrintName();
7537 PrintF("]\n");
7538 }
7539 function->ReplaceCode(function->shared()->code());
7540 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007541 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007542}
7543
7544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007545RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007546 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007547 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007548 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007549}
7550
7551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007552RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007553 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007554 ASSERT(args.length() == 1);
7555 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007556 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007557
7558 Deoptimizer::DeoptimizeFunction(*function);
7559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007560 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007561}
7562
7563
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007564RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7565 HandleScope scope(isolate);
7566 ASSERT(args.length() == 1);
7567 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7568 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7569 function->MarkForLazyRecompilation();
7570 return isolate->heap()->undefined_value();
7571}
7572
7573
lrn@chromium.org1c092762011-05-09 09:42:16 +00007574RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7575 HandleScope scope(isolate);
7576 ASSERT(args.length() == 1);
7577 if (!V8::UseCrankshaft()) {
7578 return Smi::FromInt(4); // 4 == "never".
7579 }
7580 if (FLAG_always_opt) {
7581 return Smi::FromInt(3); // 3 == "always".
7582 }
7583 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7584 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7585 : Smi::FromInt(2); // 2 == "no".
7586}
7587
7588
7589RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7590 HandleScope scope(isolate);
7591 ASSERT(args.length() == 1);
7592 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7593 return Smi::FromInt(function->shared()->opt_count());
7594}
7595
7596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007597RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007598 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007599 ASSERT(args.length() == 1);
7600 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7601
7602 // We're not prepared to handle a function with arguments object.
7603 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7604
7605 // We have hit a back edge in an unoptimized frame for a function that was
7606 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007607 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007608 // Keep track of whether we've succeeded in optimizing.
7609 bool succeeded = unoptimized->optimizable();
7610 if (succeeded) {
7611 // If we are trying to do OSR when there are already optimized
7612 // activations of the function, it means (a) the function is directly or
7613 // indirectly recursive and (b) an optimized invocation has been
7614 // deoptimized so that we are currently in an unoptimized activation.
7615 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007616 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007617 while (succeeded && !it.done()) {
7618 JavaScriptFrame* frame = it.frame();
7619 succeeded = !frame->is_optimized() || frame->function() != *function;
7620 it.Advance();
7621 }
7622 }
7623
7624 int ast_id = AstNode::kNoNumber;
7625 if (succeeded) {
7626 // The top JS function is this one, the PC is somewhere in the
7627 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007628 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007629 JavaScriptFrame* frame = it.frame();
7630 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007631 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007632 ASSERT(unoptimized->contains(frame->pc()));
7633
7634 // Use linear search of the unoptimized code's stack check table to find
7635 // the AST id matching the PC.
7636 Address start = unoptimized->instruction_start();
7637 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007638 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007639 uint32_t table_length = Memory::uint32_at(table_cursor);
7640 table_cursor += kIntSize;
7641 for (unsigned i = 0; i < table_length; ++i) {
7642 // Table entries are (AST id, pc offset) pairs.
7643 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7644 if (pc_offset == target_pc_offset) {
7645 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7646 break;
7647 }
7648 table_cursor += 2 * kIntSize;
7649 }
7650 ASSERT(ast_id != AstNode::kNoNumber);
7651 if (FLAG_trace_osr) {
7652 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7653 function->PrintName();
7654 PrintF("]\n");
7655 }
7656
7657 // Try to compile the optimized code. A true return value from
7658 // CompileOptimized means that compilation succeeded, not necessarily
7659 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007660 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7661 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007662 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7663 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007664 if (data->OsrPcOffset()->value() >= 0) {
7665 if (FLAG_trace_osr) {
7666 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007667 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007668 }
7669 ASSERT(data->OsrAstId()->value() == ast_id);
7670 } else {
7671 // We may never generate the desired OSR entry if we emit an
7672 // early deoptimize.
7673 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007674 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007675 } else {
7676 succeeded = false;
7677 }
7678 }
7679
7680 // Revert to the original stack checks in the original unoptimized code.
7681 if (FLAG_trace_osr) {
7682 PrintF("[restoring original stack checks in ");
7683 function->PrintName();
7684 PrintF("]\n");
7685 }
7686 StackCheckStub check_stub;
7687 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007688 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007689 Deoptimizer::RevertStackCheckCode(*unoptimized,
7690 *check_code,
7691 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007692
7693 // Allow OSR only at nesting level zero again.
7694 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7695
7696 // If the optimization attempt succeeded, return the AST id tagged as a
7697 // smi. This tells the builtin that we need to translate the unoptimized
7698 // frame to an optimized one.
7699 if (succeeded) {
7700 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7701 return Smi::FromInt(ast_id);
7702 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007703 if (function->IsMarkedForLazyRecompilation()) {
7704 function->ReplaceCode(function->shared()->code());
7705 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007706 return Smi::FromInt(-1);
7707 }
7708}
7709
7710
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007711RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007712 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007713 ASSERT(args.length() == 1);
7714 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7715 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7716}
7717
7718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007719RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007720 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007721 ASSERT(args.length() == 1);
7722 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7723 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7724}
7725
7726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007727RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007728 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007729 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007730
kasper.lund7276f142008-07-30 08:49:36 +00007731 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007732 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007733 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007734 { MaybeObject* maybe_result =
7735 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007736 if (!maybe_result->ToObject(&result)) return maybe_result;
7737 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007738
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007739 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007740
kasper.lund7276f142008-07-30 08:49:36 +00007741 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007742}
7743
lrn@chromium.org303ada72010-10-27 09:33:13 +00007744
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007745MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7746 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007747 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007749 Object* js_object = object;
7750 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007751 MaybeObject* maybe_js_object = js_object->ToObject();
7752 if (!maybe_js_object->ToObject(&js_object)) {
7753 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7754 return maybe_js_object;
7755 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007756 HandleScope scope(isolate);
7757 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007758 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007759 isolate->factory()->NewTypeError("with_expression",
7760 HandleVector(&handle, 1));
7761 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007762 }
7763 }
7764
lrn@chromium.org303ada72010-10-27 09:33:13 +00007765 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007766 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7767 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007768 if (!maybe_result->ToObject(&result)) return maybe_result;
7769 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007770
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007771 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007772 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007773
kasper.lund7276f142008-07-30 08:49:36 +00007774 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007775}
7776
7777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007778RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007779 NoHandleAllocation ha;
7780 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007781 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007782}
7783
7784
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007785RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007786 NoHandleAllocation ha;
7787 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007788 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007789}
7790
7791
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007792RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007793 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007794 ASSERT(args.length() == 2);
7795
7796 CONVERT_ARG_CHECKED(Context, context, 0);
7797 CONVERT_ARG_CHECKED(String, name, 1);
7798
7799 int index;
7800 PropertyAttributes attributes;
7801 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007802 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007803
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007804 // If the slot was not found the result is true.
7805 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007806 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007807 }
7808
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007809 // If the slot was found in a context, it should be DONT_DELETE.
7810 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007811 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007812 }
7813
7814 // The slot was found in a JSObject, either a context extension object,
7815 // the global object, or an arguments object. Try to delete it
7816 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7817 // which allows deleting all parameters in functions that mention
7818 // 'arguments', we do this even for the case of slots found on an
7819 // arguments object. The slot was found on an arguments object if the
7820 // index is non-negative.
7821 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7822 if (index >= 0) {
7823 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7824 } else {
7825 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7826 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007827}
7828
7829
ager@chromium.orga1645e22009-09-09 19:27:10 +00007830// A mechanism to return a pair of Object pointers in registers (if possible).
7831// How this is achieved is calling convention-dependent.
7832// All currently supported x86 compiles uses calling conventions that are cdecl
7833// variants where a 64-bit value is returned in two 32-bit registers
7834// (edx:eax on ia32, r1:r0 on ARM).
7835// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7836// In Win64 calling convention, a struct of two pointers is returned in memory,
7837// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007838#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007839struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007840 MaybeObject* x;
7841 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007842};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007843
lrn@chromium.org303ada72010-10-27 09:33:13 +00007844static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007845 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007846 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7847 // In Win64 they are assigned to a hidden first argument.
7848 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007849}
7850#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007851typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007852static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007853 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007854 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007855}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007856#endif
7857
7858
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007859static inline MaybeObject* Unhole(Heap* heap,
7860 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007861 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007862 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7863 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007864 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007865}
7866
7867
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007868static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7869 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007870 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007871 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007872 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007873 JSFunction* context_extension_function =
7874 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007875 // If the holder isn't a context extension object, we just return it
7876 // as the receiver. This allows arguments objects to be used as
7877 // receivers, but only if they are put in the context scope chain
7878 // explicitly via a with-statement.
7879 Object* constructor = holder->map()->constructor();
7880 if (constructor != context_extension_function) return holder;
7881 // Fall back to using the global object as the receiver if the
7882 // property turns out to be a local variable allocated in a context
7883 // extension object - introduced via eval.
7884 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007885}
7886
7887
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007888static ObjectPair LoadContextSlotHelper(Arguments args,
7889 Isolate* isolate,
7890 bool throw_error) {
7891 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007892 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007893
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007894 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007895 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007896 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007897 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007898 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007899
7900 int index;
7901 PropertyAttributes attributes;
7902 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007903 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007904
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007905 // If the index is non-negative, the slot has been found in a local
7906 // variable or a parameter. Read it from the context object or the
7907 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007908 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007909 // If the "property" we were looking for is a local variable or an
7910 // argument in a context, the receiver is the global object; see
7911 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007912 JSObject* receiver =
7913 isolate->context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007914 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007915 ? Context::cast(*holder)->get(index)
7916 : JSObject::cast(*holder)->GetElement(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007917 return MakePair(Unhole(isolate->heap(), value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007918 }
7919
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007920 // If the holder is found, we read the property from it.
7921 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007922 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007923 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007924 JSObject* receiver;
7925 if (object->IsGlobalObject()) {
7926 receiver = GlobalObject::cast(object)->global_receiver();
7927 } else if (context->is_exception_holder(*holder)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007928 receiver = isolate->context()->global()->global_receiver();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007929 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007930 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007931 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007932 // No need to unhole the value here. This is taken care of by the
7933 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007934 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007935 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007936 }
7937
7938 if (throw_error) {
7939 // The property doesn't exist - throw exception.
7940 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007941 isolate->factory()->NewReferenceError("not_defined",
7942 HandleVector(&name, 1));
7943 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007944 } else {
7945 // The property doesn't exist - return undefined
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007946 return MakePair(isolate->heap()->undefined_value(),
7947 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007948 }
7949}
7950
7951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007952RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007953 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007954}
7955
7956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007957RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007958 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007959}
7960
7961
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007962RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007963 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007964 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007966 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007967 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007968 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007969 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7970 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7971 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007972 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007973
7974 int index;
7975 PropertyAttributes attributes;
7976 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007977 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007978
7979 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007980 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007981 // Ignore if read_only variable.
7982 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007983 // Context is a fixed array and set cannot fail.
7984 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007985 } else if (strict_mode == kStrictMode) {
7986 // Setting read only property in strict mode.
7987 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007988 isolate->factory()->NewTypeError("strict_cannot_assign",
7989 HandleVector(&name, 1));
7990 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007991 }
7992 } else {
7993 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007994 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007995 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007996 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007997 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007998 return Failure::Exception();
7999 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008000 }
8001 return *value;
8002 }
8003
8004 // Slow case: The property is not in a FixedArray context.
8005 // It is either in an JSObject extension context or it was not found.
8006 Handle<JSObject> context_ext;
8007
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008008 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008009 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008010 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008011 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008012 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008013 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008014
8015 if (strict_mode == kStrictMode) {
8016 // Throw in strict mode (assignment to undefined variable).
8017 Handle<Object> error =
8018 isolate->factory()->NewReferenceError(
8019 "not_defined", HandleVector(&name, 1));
8020 return isolate->Throw(*error);
8021 }
8022 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008023 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008024 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008025 }
8026
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008027 // Set the property, but ignore if read_only variable on the context
8028 // extension object itself.
8029 if ((attributes & READ_ONLY) == 0 ||
8030 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008031 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008032 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008033 SetProperty(context_ext, name, value, NONE, strict_mode));
8034 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008035 // Setting read only property in strict mode.
8036 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008037 isolate->factory()->NewTypeError(
8038 "strict_cannot_assign", HandleVector(&name, 1));
8039 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008040 }
8041 return *value;
8042}
8043
8044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008045RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008046 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008047 ASSERT(args.length() == 1);
8048
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008049 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008050}
8051
8052
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008053RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008054 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008055 ASSERT(args.length() == 1);
8056
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008057 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008058}
8059
8060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008061RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008062 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008063 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008064}
8065
8066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008067RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008068 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008069 ASSERT(args.length() == 1);
8070
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008071 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008072 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008073 isolate->factory()->NewReferenceError("not_defined",
8074 HandleVector(&name, 1));
8075 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008076}
8077
8078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008079RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008080 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008081
8082 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008083 if (isolate->stack_guard()->IsStackOverflow()) {
8084 NoHandleAllocation na;
8085 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008086 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008087
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008088 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008089}
8090
8091
8092// NOTE: These PrintXXX functions are defined for all builds (not just
8093// DEBUG builds) because we may want to be able to trace function
8094// calls in all modes.
8095static void PrintString(String* str) {
8096 // not uncommon to have empty strings
8097 if (str->length() > 0) {
8098 SmartPointer<char> s =
8099 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8100 PrintF("%s", *s);
8101 }
8102}
8103
8104
8105static void PrintObject(Object* obj) {
8106 if (obj->IsSmi()) {
8107 PrintF("%d", Smi::cast(obj)->value());
8108 } else if (obj->IsString() || obj->IsSymbol()) {
8109 PrintString(String::cast(obj));
8110 } else if (obj->IsNumber()) {
8111 PrintF("%g", obj->Number());
8112 } else if (obj->IsFailure()) {
8113 PrintF("<failure>");
8114 } else if (obj->IsUndefined()) {
8115 PrintF("<undefined>");
8116 } else if (obj->IsNull()) {
8117 PrintF("<null>");
8118 } else if (obj->IsTrue()) {
8119 PrintF("<true>");
8120 } else if (obj->IsFalse()) {
8121 PrintF("<false>");
8122 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008123 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008124 }
8125}
8126
8127
8128static int StackSize() {
8129 int n = 0;
8130 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8131 return n;
8132}
8133
8134
8135static void PrintTransition(Object* result) {
8136 // indentation
8137 { const int nmax = 80;
8138 int n = StackSize();
8139 if (n <= nmax)
8140 PrintF("%4d:%*s", n, n, "");
8141 else
8142 PrintF("%4d:%*s", n, nmax, "...");
8143 }
8144
8145 if (result == NULL) {
8146 // constructor calls
8147 JavaScriptFrameIterator it;
8148 JavaScriptFrame* frame = it.frame();
8149 if (frame->IsConstructor()) PrintF("new ");
8150 // function name
8151 Object* fun = frame->function();
8152 if (fun->IsJSFunction()) {
8153 PrintObject(JSFunction::cast(fun)->shared()->name());
8154 } else {
8155 PrintObject(fun);
8156 }
8157 // function arguments
8158 // (we are intentionally only printing the actually
8159 // supplied parameters, not all parameters required)
8160 PrintF("(this=");
8161 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008162 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008163 for (int i = 0; i < length; i++) {
8164 PrintF(", ");
8165 PrintObject(frame->GetParameter(i));
8166 }
8167 PrintF(") {\n");
8168
8169 } else {
8170 // function result
8171 PrintF("} -> ");
8172 PrintObject(result);
8173 PrintF("\n");
8174 }
8175}
8176
8177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008178RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008179 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008180 NoHandleAllocation ha;
8181 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008182 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008183}
8184
8185
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008186RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008187 NoHandleAllocation ha;
8188 PrintTransition(args[0]);
8189 return args[0]; // return TOS
8190}
8191
8192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008193RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008194 NoHandleAllocation ha;
8195 ASSERT(args.length() == 1);
8196
8197#ifdef DEBUG
8198 if (args[0]->IsString()) {
8199 // If we have a string, assume it's a code "marker"
8200 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008201 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008202 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008203 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8204 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008205 } else {
8206 PrintF("DebugPrint: ");
8207 }
8208 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008209 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008210 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008211 HeapObject::cast(args[0])->map()->Print();
8212 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008213#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008214 // ShortPrint is available in release mode. Print is not.
8215 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008216#endif
8217 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008218 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008219
8220 return args[0]; // return TOS
8221}
8222
8223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008224RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008225 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008226 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008227 isolate->PrintStack();
8228 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008229}
8230
8231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008232RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008233 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008234 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008235
8236 // According to ECMA-262, section 15.9.1, page 117, the precision of
8237 // the number in a Date object representing a particular instant in
8238 // time is milliseconds. Therefore, we floor the result of getting
8239 // the OS time.
8240 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008241 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008242}
8243
8244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008245RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008246 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008247 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008248
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008249 CONVERT_ARG_CHECKED(String, str, 0);
8250 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008251
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008252 CONVERT_ARG_CHECKED(JSArray, output, 1);
8253 RUNTIME_ASSERT(output->HasFastElements());
8254
8255 AssertNoAllocation no_allocation;
8256
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008257 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008258 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8259 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008260 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008261 result = DateParser::Parse(str->ToAsciiVector(),
8262 output_array,
8263 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008264 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008265 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008266 result = DateParser::Parse(str->ToUC16Vector(),
8267 output_array,
8268 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008269 }
8270
8271 if (result) {
8272 return *output;
8273 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008274 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008275 }
8276}
8277
8278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008279RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008280 NoHandleAllocation ha;
8281 ASSERT(args.length() == 1);
8282
8283 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008284 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008285 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008286}
8287
8288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008289RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008290 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008291 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008292
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008293 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008294}
8295
8296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008297RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008298 NoHandleAllocation ha;
8299 ASSERT(args.length() == 1);
8300
8301 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008302 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008303}
8304
8305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008306RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008307 ASSERT(args.length() == 1);
8308 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008309 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008310 return JSGlobalObject::cast(global)->global_receiver();
8311}
8312
8313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008314RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008315 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008316 ASSERT_EQ(1, args.length());
8317 CONVERT_ARG_CHECKED(String, source, 0);
8318
8319 Handle<Object> result = JsonParser::Parse(source);
8320 if (result.is_null()) {
8321 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008322 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008323 return Failure::Exception();
8324 }
8325 return *result;
8326}
8327
8328
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008329bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8330 Handle<Context> context) {
8331 if (context->allow_code_gen_from_strings()->IsFalse()) {
8332 // Check with callback if set.
8333 AllowCodeGenerationFromStringsCallback callback =
8334 isolate->allow_code_gen_callback();
8335 if (callback == NULL) {
8336 // No callback set and code generation disallowed.
8337 return false;
8338 } else {
8339 // Callback set. Let it decide if code generation is allowed.
8340 VMState state(isolate, EXTERNAL);
8341 return callback(v8::Utils::ToLocal(context));
8342 }
8343 }
8344 return true;
8345}
8346
8347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008348RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008349 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008350 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008351 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008352
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008353 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008354 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008355
8356 // Check if global context allows code generation from
8357 // strings. Throw an exception if it doesn't.
8358 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8359 return isolate->Throw(*isolate->factory()->NewError(
8360 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8361 }
8362
8363 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008364 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8365 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008366 true,
8367 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008368 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008369 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008370 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8371 context,
8372 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008373 return *fun;
8374}
8375
8376
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008377static ObjectPair CompileGlobalEval(Isolate* isolate,
8378 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008379 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008380 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008381 Handle<Context> context = Handle<Context>(isolate->context());
8382 Handle<Context> global_context = Handle<Context>(context->global_context());
8383
8384 // Check if global context allows code generation from
8385 // strings. Throw an exception if it doesn't.
8386 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8387 isolate->Throw(*isolate->factory()->NewError(
8388 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8389 return MakePair(Failure::Exception(), NULL);
8390 }
8391
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008392 // Deal with a normal eval call with a string argument. Compile it
8393 // and return the compiled function bound in the local context.
8394 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8395 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008396 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008397 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008398 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008399 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008400 Handle<JSFunction> compiled =
8401 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008402 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008403 return MakePair(*compiled, *receiver);
8404}
8405
8406
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008407RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008408 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008409
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008410 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008411 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008412 Handle<Object> receiver; // Will be overwritten.
8413
8414 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008415 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008416#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008417 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008418 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008419 StackFrameLocator locator;
8420 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008421 ASSERT(Context::cast(frame->context()) == *context);
8422#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008423
8424 // Find where the 'eval' symbol is bound. It is unaliased only if
8425 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008426 int index = -1;
8427 PropertyAttributes attributes = ABSENT;
8428 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008429 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8430 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008431 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008432 // Stop search when eval is found or when the global context is
8433 // reached.
8434 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008435 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008436 context = Handle<Context>(Context::cast(context->closure()->context()),
8437 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008438 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008439 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008440 }
8441 }
8442
iposva@chromium.org245aa852009-02-10 00:49:54 +00008443 // If eval could not be resolved, it has been deleted and we need to
8444 // throw a reference error.
8445 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008446 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008447 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008448 isolate->factory()->NewReferenceError("not_defined",
8449 HandleVector(&name, 1));
8450 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008451 }
8452
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008453 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008454 // 'eval' is not bound in the global context. Just call the function
8455 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008456 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008457 receiver = Handle<JSObject>(
8458 isolate->context()->global()->global_receiver(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008459 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008460 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008461 }
8462
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008463 // 'eval' is bound in the global context, but it may have been overwritten.
8464 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008465 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008466 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008467 return MakePair(*callee,
8468 isolate->context()->global()->global_receiver());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008469 }
8470
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008471 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008472 return CompileGlobalEval(isolate,
8473 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008474 args.at<Object>(2),
8475 static_cast<StrictModeFlag>(
8476 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008477}
8478
8479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008480RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008481 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008482
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008483 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008484 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008485
8486 // 'eval' is bound in the global context, but it may have been overwritten.
8487 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008488 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008489 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 return MakePair(*callee,
8491 isolate->context()->global()->global_receiver());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008492 }
8493
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008494 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008495 return CompileGlobalEval(isolate,
8496 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008497 args.at<Object>(2),
8498 static_cast<StrictModeFlag>(
8499 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008500}
8501
8502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008503RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008504 // This utility adjusts the property attributes for newly created Function
8505 // object ("new Function(...)") by changing the map.
8506 // All it does is changing the prototype property to enumerable
8507 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008508 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008509 ASSERT(args.length() == 1);
8510 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008511
8512 Handle<Map> map = func->shared()->strict_mode()
8513 ? isolate->strict_mode_function_instance_map()
8514 : isolate->function_instance_map();
8515
8516 ASSERT(func->map()->instance_type() == map->instance_type());
8517 ASSERT(func->map()->instance_size() == map->instance_size());
8518 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008519 return *func;
8520}
8521
8522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008523RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008524 // Allocate a block of memory in NewSpace (filled with a filler).
8525 // Use as fallback for allocation in generated code when NewSpace
8526 // is full.
8527 ASSERT(args.length() == 1);
8528 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8529 int size = size_smi->value();
8530 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8531 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008532 Heap* heap = isolate->heap();
8533 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008534 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008535 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008536 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008537 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008538 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008539 }
8540 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008541 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008542}
8543
8544
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008545// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008546// array. Returns true if the element was pushed on the stack and
8547// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008548RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008549 ASSERT(args.length() == 2);
8550 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008551 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008552 RUNTIME_ASSERT(array->HasFastElements());
8553 int length = Smi::cast(array->length())->value();
8554 FixedArray* elements = FixedArray::cast(array->elements());
8555 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008556 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008557 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008558 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008559 // Strict not needed. Used for cycle detection in Array join implementation.
8560 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8561 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008562 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8563 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008564 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008565}
8566
8567
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008568/**
8569 * A simple visitor visits every element of Array's.
8570 * The backend storage can be a fixed array for fast elements case,
8571 * or a dictionary for sparse array. Since Dictionary is a subtype
8572 * of FixedArray, the class can be used by both fast and slow cases.
8573 * The second parameter of the constructor, fast_elements, specifies
8574 * whether the storage is a FixedArray or Dictionary.
8575 *
8576 * An index limit is used to deal with the situation that a result array
8577 * length overflows 32-bit non-negative integer.
8578 */
8579class ArrayConcatVisitor {
8580 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008581 ArrayConcatVisitor(Isolate* isolate,
8582 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008583 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008584 isolate_(isolate),
8585 storage_(Handle<FixedArray>::cast(
8586 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008587 index_offset_(0u),
8588 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008589
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008590 ~ArrayConcatVisitor() {
8591 clear_storage();
8592 }
8593
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008594 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008595 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008596 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008597
8598 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008599 if (index < static_cast<uint32_t>(storage_->length())) {
8600 storage_->set(index, *elm);
8601 return;
8602 }
8603 // Our initial estimate of length was foiled, possibly by
8604 // getters on the arrays increasing the length of later arrays
8605 // during iteration.
8606 // This shouldn't happen in anything but pathological cases.
8607 SetDictionaryMode(index);
8608 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008609 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008610 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008611 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008612 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008613 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008614 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008615 // Dictionary needed to grow.
8616 clear_storage();
8617 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008618 }
8619}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008620
8621 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008622 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8623 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008624 } else {
8625 index_offset_ += delta;
8626 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008627 }
8628
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008629 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008630 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008631 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008632 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008633 Handle<Map> map;
8634 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008635 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008636 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008637 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008638 }
8639 array->set_map(*map);
8640 array->set_length(*length);
8641 array->set_elements(*storage_);
8642 return array;
8643 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008644
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008645 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008646 // Convert storage to dictionary mode.
8647 void SetDictionaryMode(uint32_t index) {
8648 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008649 Handle<FixedArray> current_storage(*storage_);
8650 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008651 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008652 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8653 for (uint32_t i = 0; i < current_length; i++) {
8654 HandleScope loop_scope;
8655 Handle<Object> element(current_storage->get(i));
8656 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008657 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008658 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008659 if (!new_storage.is_identical_to(slow_storage)) {
8660 slow_storage = loop_scope.CloseAndEscape(new_storage);
8661 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008662 }
8663 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008664 clear_storage();
8665 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008666 fast_elements_ = false;
8667 }
8668
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008669 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008670 isolate_->global_handles()->Destroy(
8671 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008672 }
8673
8674 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008675 storage_ = Handle<FixedArray>::cast(
8676 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008677 }
8678
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008679 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008680 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008681 // Index after last seen index. Always less than or equal to
8682 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008683 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008684 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008685};
8686
8687
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008688static uint32_t EstimateElementCount(Handle<JSArray> array) {
8689 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8690 int element_count = 0;
8691 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008692 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008693 // Fast elements can't have lengths that are not representable by
8694 // a 32-bit signed integer.
8695 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8696 int fast_length = static_cast<int>(length);
8697 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8698 for (int i = 0; i < fast_length; i++) {
8699 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008700 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008701 break;
8702 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008703 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008704 Handle<NumberDictionary> dictionary(
8705 NumberDictionary::cast(array->elements()));
8706 int capacity = dictionary->Capacity();
8707 for (int i = 0; i < capacity; i++) {
8708 Handle<Object> key(dictionary->KeyAt(i));
8709 if (dictionary->IsKey(*key)) {
8710 element_count++;
8711 }
8712 }
8713 break;
8714 }
8715 default:
8716 // External arrays are always dense.
8717 return length;
8718 }
8719 // As an estimate, we assume that the prototype doesn't contain any
8720 // inherited elements.
8721 return element_count;
8722}
8723
8724
8725
8726template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008727static void IterateExternalArrayElements(Isolate* isolate,
8728 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008729 bool elements_are_ints,
8730 bool elements_are_guaranteed_smis,
8731 ArrayConcatVisitor* visitor) {
8732 Handle<ExternalArrayClass> array(
8733 ExternalArrayClass::cast(receiver->elements()));
8734 uint32_t len = static_cast<uint32_t>(array->length());
8735
8736 ASSERT(visitor != NULL);
8737 if (elements_are_ints) {
8738 if (elements_are_guaranteed_smis) {
8739 for (uint32_t j = 0; j < len; j++) {
8740 HandleScope loop_scope;
8741 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8742 visitor->visit(j, e);
8743 }
8744 } else {
8745 for (uint32_t j = 0; j < len; j++) {
8746 HandleScope loop_scope;
8747 int64_t val = static_cast<int64_t>(array->get(j));
8748 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8749 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8750 visitor->visit(j, e);
8751 } else {
8752 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008753 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008754 visitor->visit(j, e);
8755 }
8756 }
8757 }
8758 } else {
8759 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008760 HandleScope loop_scope(isolate);
8761 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008762 visitor->visit(j, e);
8763 }
8764 }
8765}
8766
8767
8768// Used for sorting indices in a List<uint32_t>.
8769static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8770 uint32_t a = *ap;
8771 uint32_t b = *bp;
8772 return (a == b) ? 0 : (a < b) ? -1 : 1;
8773}
8774
8775
8776static void CollectElementIndices(Handle<JSObject> object,
8777 uint32_t range,
8778 List<uint32_t>* indices) {
8779 JSObject::ElementsKind kind = object->GetElementsKind();
8780 switch (kind) {
8781 case JSObject::FAST_ELEMENTS: {
8782 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8783 uint32_t length = static_cast<uint32_t>(elements->length());
8784 if (range < length) length = range;
8785 for (uint32_t i = 0; i < length; i++) {
8786 if (!elements->get(i)->IsTheHole()) {
8787 indices->Add(i);
8788 }
8789 }
8790 break;
8791 }
8792 case JSObject::DICTIONARY_ELEMENTS: {
8793 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008794 uint32_t capacity = dict->Capacity();
8795 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008796 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008797 Handle<Object> k(dict->KeyAt(j));
8798 if (dict->IsKey(*k)) {
8799 ASSERT(k->IsNumber());
8800 uint32_t index = static_cast<uint32_t>(k->Number());
8801 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008802 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008803 }
8804 }
8805 }
8806 break;
8807 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008808 default: {
8809 int dense_elements_length;
8810 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008811 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008812 dense_elements_length =
8813 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008814 break;
8815 }
8816 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008817 dense_elements_length =
8818 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008819 break;
8820 }
8821 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008822 dense_elements_length =
8823 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008824 break;
8825 }
8826 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008827 dense_elements_length =
8828 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008829 break;
8830 }
8831 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008832 dense_elements_length =
8833 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008834 break;
8835 }
8836 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008837 dense_elements_length =
8838 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008839 break;
8840 }
8841 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008842 dense_elements_length =
8843 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008844 break;
8845 }
8846 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008847 dense_elements_length =
8848 ExternalFloatArray::cast(object->elements())->length();
8849 break;
8850 }
8851 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8852 dense_elements_length =
8853 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008854 break;
8855 }
8856 default:
8857 UNREACHABLE();
8858 dense_elements_length = 0;
8859 break;
8860 }
8861 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8862 if (range <= length) {
8863 length = range;
8864 // We will add all indices, so we might as well clear it first
8865 // and avoid duplicates.
8866 indices->Clear();
8867 }
8868 for (uint32_t i = 0; i < length; i++) {
8869 indices->Add(i);
8870 }
8871 if (length == range) return; // All indices accounted for already.
8872 break;
8873 }
8874 }
8875
8876 Handle<Object> prototype(object->GetPrototype());
8877 if (prototype->IsJSObject()) {
8878 // The prototype will usually have no inherited element indices,
8879 // but we have to check.
8880 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8881 }
8882}
8883
8884
8885/**
8886 * A helper function that visits elements of a JSArray in numerical
8887 * order.
8888 *
8889 * The visitor argument called for each existing element in the array
8890 * with the element index and the element's value.
8891 * Afterwards it increments the base-index of the visitor by the array
8892 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008893 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008894 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008895static bool IterateElements(Isolate* isolate,
8896 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008897 ArrayConcatVisitor* visitor) {
8898 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8899 switch (receiver->GetElementsKind()) {
8900 case JSObject::FAST_ELEMENTS: {
8901 // Run through the elements FixedArray and use HasElement and GetElement
8902 // to check the prototype for missing elements.
8903 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8904 int fast_length = static_cast<int>(length);
8905 ASSERT(fast_length <= elements->length());
8906 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008907 HandleScope loop_scope(isolate);
8908 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008909 if (!element_value->IsTheHole()) {
8910 visitor->visit(j, element_value);
8911 } else if (receiver->HasElement(j)) {
8912 // Call GetElement on receiver, not its prototype, or getters won't
8913 // have the correct receiver.
8914 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008915 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008916 visitor->visit(j, element_value);
8917 }
8918 }
8919 break;
8920 }
8921 case JSObject::DICTIONARY_ELEMENTS: {
8922 Handle<NumberDictionary> dict(receiver->element_dictionary());
8923 List<uint32_t> indices(dict->Capacity() / 2);
8924 // Collect all indices in the object and the prototypes less
8925 // than length. This might introduce duplicates in the indices list.
8926 CollectElementIndices(receiver, length, &indices);
8927 indices.Sort(&compareUInt32);
8928 int j = 0;
8929 int n = indices.length();
8930 while (j < n) {
8931 HandleScope loop_scope;
8932 uint32_t index = indices[j];
8933 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008934 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008935 visitor->visit(index, element);
8936 // Skip to next different index (i.e., omit duplicates).
8937 do {
8938 j++;
8939 } while (j < n && indices[j] == index);
8940 }
8941 break;
8942 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008943 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8944 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8945 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008946 for (uint32_t j = 0; j < length; j++) {
8947 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8948 visitor->visit(j, e);
8949 }
8950 break;
8951 }
8952 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8953 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008954 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008955 break;
8956 }
8957 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8958 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008959 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008960 break;
8961 }
8962 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8963 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008964 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008965 break;
8966 }
8967 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8968 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008969 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008970 break;
8971 }
8972 case JSObject::EXTERNAL_INT_ELEMENTS: {
8973 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008974 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008975 break;
8976 }
8977 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8978 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008979 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008980 break;
8981 }
8982 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8983 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008984 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008985 break;
8986 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008987 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8988 IterateExternalArrayElements<ExternalDoubleArray, double>(
8989 isolate, receiver, false, false, visitor);
8990 break;
8991 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008992 default:
8993 UNREACHABLE();
8994 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008995 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008996 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008997 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008998}
8999
9000
9001/**
9002 * Array::concat implementation.
9003 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009004 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009005 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009006 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009007RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009008 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009009 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009010
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009011 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9012 int argument_count = static_cast<int>(arguments->length()->Number());
9013 RUNTIME_ASSERT(arguments->HasFastElements());
9014 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009015
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009016 // Pass 1: estimate the length and number of elements of the result.
9017 // The actual length can be larger if any of the arguments have getters
9018 // that mutate other arguments (but will otherwise be precise).
9019 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009020
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009021 uint32_t estimate_result_length = 0;
9022 uint32_t estimate_nof_elements = 0;
9023 {
9024 for (int i = 0; i < argument_count; i++) {
9025 HandleScope loop_scope;
9026 Handle<Object> obj(elements->get(i));
9027 uint32_t length_estimate;
9028 uint32_t element_estimate;
9029 if (obj->IsJSArray()) {
9030 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9031 length_estimate =
9032 static_cast<uint32_t>(array->length()->Number());
9033 element_estimate =
9034 EstimateElementCount(array);
9035 } else {
9036 length_estimate = 1;
9037 element_estimate = 1;
9038 }
9039 // Avoid overflows by capping at kMaxElementCount.
9040 if (JSObject::kMaxElementCount - estimate_result_length <
9041 length_estimate) {
9042 estimate_result_length = JSObject::kMaxElementCount;
9043 } else {
9044 estimate_result_length += length_estimate;
9045 }
9046 if (JSObject::kMaxElementCount - estimate_nof_elements <
9047 element_estimate) {
9048 estimate_nof_elements = JSObject::kMaxElementCount;
9049 } else {
9050 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009051 }
9052 }
9053 }
9054
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009055 // If estimated number of elements is more than half of length, a
9056 // fixed array (fast case) is more time and space-efficient than a
9057 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009058 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009059
9060 Handle<FixedArray> storage;
9061 if (fast_case) {
9062 // The backing storage array must have non-existing elements to
9063 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009064 storage = isolate->factory()->NewFixedArrayWithHoles(
9065 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009066 } else {
9067 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9068 uint32_t at_least_space_for = estimate_nof_elements +
9069 (estimate_nof_elements >> 2);
9070 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009071 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009072 }
9073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009074 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009075
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009076 for (int i = 0; i < argument_count; i++) {
9077 Handle<Object> obj(elements->get(i));
9078 if (obj->IsJSArray()) {
9079 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009080 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009081 return Failure::Exception();
9082 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009083 } else {
9084 visitor.visit(0, obj);
9085 visitor.increase_index_offset(1);
9086 }
9087 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009088
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009089 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009090}
9091
9092
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009093// This will not allocate (flatten the string), but it may run
9094// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009095RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009096 NoHandleAllocation ha;
9097 ASSERT(args.length() == 1);
9098
9099 CONVERT_CHECKED(String, string, args[0]);
9100 StringInputBuffer buffer(string);
9101 while (buffer.has_more()) {
9102 uint16_t character = buffer.GetNext();
9103 PrintF("%c", character);
9104 }
9105 return string;
9106}
9107
ager@chromium.org5ec48922009-05-05 07:25:34 +00009108// Moves all own elements of an object, that are below a limit, to positions
9109// starting at zero. All undefined values are placed after non-undefined values,
9110// and are followed by non-existing element. Does not change the length
9111// property.
9112// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009113RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009114 ASSERT(args.length() == 2);
9115 CONVERT_CHECKED(JSObject, object, args[0]);
9116 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9117 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009118}
9119
9120
9121// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009122RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009123 ASSERT(args.length() == 2);
9124 CONVERT_CHECKED(JSArray, from, args[0]);
9125 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009126 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009127 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009128 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9129 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009130 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009131 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009132 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009133 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009134 Object* new_map;
9135 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009136 to->set_map(Map::cast(new_map));
9137 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009138 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009139 Object* obj;
9140 { MaybeObject* maybe_obj = from->ResetElements();
9141 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9142 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009143 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009144 return to;
9145}
9146
9147
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009148// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009149RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009150 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009151 CONVERT_CHECKED(JSObject, object, args[0]);
9152 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009153 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009154 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009155 } else if (object->IsJSArray()) {
9156 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009157 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009158 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159 }
9160}
9161
9162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009163RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009164 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009165
9166 ASSERT_EQ(3, args.length());
9167
ager@chromium.orgac091b72010-05-05 07:34:42 +00009168 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009169 Handle<Object> key1 = args.at<Object>(1);
9170 Handle<Object> key2 = args.at<Object>(2);
9171
9172 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009173 if (!key1->ToArrayIndex(&index1)
9174 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009175 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009176 }
9177
ager@chromium.orgac091b72010-05-05 07:34:42 +00009178 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9179 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009180 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009181 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009182 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009183
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009184 RETURN_IF_EMPTY_HANDLE(isolate,
9185 SetElement(jsobject, index1, tmp2, kStrictMode));
9186 RETURN_IF_EMPTY_HANDLE(isolate,
9187 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009188
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009189 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009190}
9191
9192
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009193// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009194// might have elements. Can either return keys (positive integers) or
9195// intervals (pair of a negative integer (-start-1) followed by a
9196// positive (length)) or undefined values.
9197// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009198RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009199 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009200 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009201 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009202 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009203 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009204 // Create an array and get all the keys into it, then remove all the
9205 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009206 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009207 int keys_length = keys->length();
9208 for (int i = 0; i < keys_length; i++) {
9209 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009210 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009211 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009212 // Zap invalid keys.
9213 keys->set_undefined(i);
9214 }
9215 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009216 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009217 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009218 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009219 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009220 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009221 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009222 uint32_t actual_length =
9223 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009224 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009225 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009226 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009227 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009228 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009229 }
9230}
9231
9232
9233// DefineAccessor takes an optional final argument which is the
9234// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9235// to the way accessors are implemented, it is set for both the getter
9236// and setter on the first call to DefineAccessor and ignored on
9237// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009238RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009239 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9240 // Compute attributes.
9241 PropertyAttributes attributes = NONE;
9242 if (args.length() == 5) {
9243 CONVERT_CHECKED(Smi, attrs, args[4]);
9244 int value = attrs->value();
9245 // Only attribute bits should be set.
9246 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9247 attributes = static_cast<PropertyAttributes>(value);
9248 }
9249
9250 CONVERT_CHECKED(JSObject, obj, args[0]);
9251 CONVERT_CHECKED(String, name, args[1]);
9252 CONVERT_CHECKED(Smi, flag, args[2]);
9253 CONVERT_CHECKED(JSFunction, fun, args[3]);
9254 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9255}
9256
9257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009258RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009259 ASSERT(args.length() == 3);
9260 CONVERT_CHECKED(JSObject, obj, args[0]);
9261 CONVERT_CHECKED(String, name, args[1]);
9262 CONVERT_CHECKED(Smi, flag, args[2]);
9263 return obj->LookupAccessor(name, flag->value() == 0);
9264}
9265
9266
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009267#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009268RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009269 ASSERT(args.length() == 0);
9270 return Execution::DebugBreakHelper();
9271}
9272
9273
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009274// Helper functions for wrapping and unwrapping stack frame ids.
9275static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009276 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009277 return Smi::FromInt(id >> 2);
9278}
9279
9280
9281static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9282 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9283}
9284
9285
9286// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009287// args[0]: debug event listener function to set or null or undefined for
9288// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009289// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009290RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009291 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009292 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9293 args[0]->IsUndefined() ||
9294 args[0]->IsNull());
9295 Handle<Object> callback = args.at<Object>(0);
9296 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009297 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009298
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009299 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009300}
9301
9302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009303RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009304 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009305 isolate->stack_guard()->DebugBreak();
9306 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009307}
9308
9309
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009310static MaybeObject* DebugLookupResultValue(Heap* heap,
9311 Object* receiver,
9312 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009313 LookupResult* result,
9314 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009315 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009316 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009317 case NORMAL:
9318 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009319 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009320 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009321 }
9322 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009323 case FIELD:
9324 value =
9325 JSObject::cast(
9326 result->holder())->FastPropertyAt(result->GetFieldIndex());
9327 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009328 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009329 }
9330 return value;
9331 case CONSTANT_FUNCTION:
9332 return result->GetConstantFunction();
9333 case CALLBACKS: {
9334 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009335 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009336 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009337 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009338 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009339 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009340 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009341 maybe_value = heap->isolate()->pending_exception();
9342 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009343 if (caught_exception != NULL) {
9344 *caught_exception = true;
9345 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009346 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009347 }
9348 return value;
9349 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009350 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009351 }
9352 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009353 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009354 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009355 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009356 case CONSTANT_TRANSITION:
9357 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009358 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009359 default:
9360 UNREACHABLE();
9361 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009362 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009363 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009364}
9365
9366
ager@chromium.org32912102009-01-16 10:38:43 +00009367// Get debugger related details for an object property.
9368// args[0]: object holding property
9369// args[1]: name of the property
9370//
9371// The array returned contains the following information:
9372// 0: Property value
9373// 1: Property details
9374// 2: Property value is exception
9375// 3: Getter function if defined
9376// 4: Setter function if defined
9377// Items 2-4 are only filled if the property has either a getter or a setter
9378// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009379RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009380 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009381
9382 ASSERT(args.length() == 2);
9383
9384 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9385 CONVERT_ARG_CHECKED(String, name, 1);
9386
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009387 // Make sure to set the current context to the context before the debugger was
9388 // entered (if the debugger is entered). The reason for switching context here
9389 // is that for some property lookups (accessors and interceptors) callbacks
9390 // into the embedding application can occour, and the embedding application
9391 // could have the assumption that its own global context is the current
9392 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009393 SaveContext save(isolate);
9394 if (isolate->debug()->InDebugger()) {
9395 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009396 }
9397
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009398 // Skip the global proxy as it has no properties and always delegates to the
9399 // real global object.
9400 if (obj->IsJSGlobalProxy()) {
9401 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9402 }
9403
9404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009405 // Check if the name is trivially convertible to an index and get the element
9406 // if so.
9407 uint32_t index;
9408 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009409 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009410 Object* element_or_char;
9411 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009412 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009413 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9414 return maybe_element_or_char;
9415 }
9416 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009417 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009418 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009419 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009420 }
9421
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009422 // Find the number of objects making up this.
9423 int length = LocalPrototypeChainLength(*obj);
9424
9425 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009426 Handle<JSObject> jsproto = obj;
9427 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009428 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009429 jsproto->LocalLookup(*name, &result);
9430 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009431 // LookupResult is not GC safe as it holds raw object pointers.
9432 // GC can happen later in this code so put the required fields into
9433 // local variables using handles when required for later use.
9434 PropertyType result_type = result.type();
9435 Handle<Object> result_callback_obj;
9436 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009437 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9438 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009439 }
9440 Smi* property_details = result.GetPropertyDetails().AsSmi();
9441 // DebugLookupResultValue can cause GC so details from LookupResult needs
9442 // to be copied to handles before this.
9443 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009444 Object* raw_value;
9445 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009446 DebugLookupResultValue(isolate->heap(), *obj, *name,
9447 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009448 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9449 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009450 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009451
9452 // If the callback object is a fixed array then it contains JavaScript
9453 // getter and/or setter.
9454 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9455 result_callback_obj->IsFixedArray();
9456 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009457 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009458 details->set(0, *value);
9459 details->set(1, property_details);
9460 if (hasJavaScriptAccessors) {
9461 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009462 caught_exception ? isolate->heap()->true_value()
9463 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009464 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9465 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9466 }
9467
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009468 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009469 }
9470 if (i < length - 1) {
9471 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9472 }
9473 }
9474
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009475 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009476}
9477
9478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009479RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009480 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009481
9482 ASSERT(args.length() == 2);
9483
9484 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9485 CONVERT_ARG_CHECKED(String, name, 1);
9486
9487 LookupResult result;
9488 obj->Lookup(*name, &result);
9489 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009490 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009491 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009492 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009493}
9494
9495
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009496// Return the property type calculated from the property details.
9497// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009498RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009499 ASSERT(args.length() == 1);
9500 CONVERT_CHECKED(Smi, details, args[0]);
9501 PropertyType type = PropertyDetails(details).type();
9502 return Smi::FromInt(static_cast<int>(type));
9503}
9504
9505
9506// Return the property attribute calculated from the property details.
9507// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009508RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009509 ASSERT(args.length() == 1);
9510 CONVERT_CHECKED(Smi, details, args[0]);
9511 PropertyAttributes attributes = PropertyDetails(details).attributes();
9512 return Smi::FromInt(static_cast<int>(attributes));
9513}
9514
9515
9516// Return the property insertion index calculated from the property details.
9517// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009518RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009519 ASSERT(args.length() == 1);
9520 CONVERT_CHECKED(Smi, details, args[0]);
9521 int index = PropertyDetails(details).index();
9522 return Smi::FromInt(index);
9523}
9524
9525
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009526// Return property value from named interceptor.
9527// args[0]: object
9528// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009529RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009530 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009531 ASSERT(args.length() == 2);
9532 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9533 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9534 CONVERT_ARG_CHECKED(String, name, 1);
9535
9536 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009537 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009538}
9539
9540
9541// Return element value from indexed interceptor.
9542// args[0]: object
9543// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009544RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009545 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009546 ASSERT(args.length() == 2);
9547 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9548 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9549 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9550
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009551 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009552}
9553
9554
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009555RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009556 ASSERT(args.length() >= 1);
9557 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009558 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009559 if (isolate->debug()->break_id() == 0 ||
9560 break_id != isolate->debug()->break_id()) {
9561 return isolate->Throw(
9562 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009563 }
9564
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009565 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009566}
9567
9568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009569RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009570 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009571 ASSERT(args.length() == 1);
9572
9573 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009574 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009575 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9576 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009577 if (!maybe_result->ToObject(&result)) return maybe_result;
9578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009579
9580 // Count all frames which are relevant to debugging stack trace.
9581 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009582 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009583 if (id == StackFrame::NO_ID) {
9584 // If there is no JavaScript stack frame count is 0.
9585 return Smi::FromInt(0);
9586 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009587 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009588 return Smi::FromInt(n);
9589}
9590
9591
9592static const int kFrameDetailsFrameIdIndex = 0;
9593static const int kFrameDetailsReceiverIndex = 1;
9594static const int kFrameDetailsFunctionIndex = 2;
9595static const int kFrameDetailsArgumentCountIndex = 3;
9596static const int kFrameDetailsLocalCountIndex = 4;
9597static const int kFrameDetailsSourcePositionIndex = 5;
9598static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009599static const int kFrameDetailsAtReturnIndex = 7;
9600static const int kFrameDetailsDebuggerFrameIndex = 8;
9601static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009602
9603// Return an array with frame details
9604// args[0]: number: break id
9605// args[1]: number: frame index
9606//
9607// The array returned contains the following information:
9608// 0: Frame id
9609// 1: Receiver
9610// 2: Function
9611// 3: Argument count
9612// 4: Local count
9613// 5: Source position
9614// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009615// 7: Is at return
9616// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009617// Arguments name, value
9618// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009619// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009620RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009621 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009622 ASSERT(args.length() == 2);
9623
9624 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009625 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009626 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9627 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009628 if (!maybe_check->ToObject(&check)) return maybe_check;
9629 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009630 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009631 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009632
9633 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009634 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009635 if (id == StackFrame::NO_ID) {
9636 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009637 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009638 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009639 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009640 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009641 for (; !it.done(); it.Advance()) {
9642 if (count == index) break;
9643 count++;
9644 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009645 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009646
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009647 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009648 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009649
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009650 // Traverse the saved contexts chain to find the active context for the
9651 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009652 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009653 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009654 save = save->prev();
9655 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009656 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009657
9658 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009659 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009660
9661 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009662 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009663 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009664
9665 // Check for constructor frame.
9666 bool constructor = it.frame()->IsConstructor();
9667
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009668 // Get scope info and read from it for local variable information.
9669 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009670 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009671 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009672
9673 // Get the context.
9674 Handle<Context> context(Context::cast(it.frame()->context()));
9675
9676 // Get the locals names and values into a temporary array.
9677 //
9678 // TODO(1240907): Hide compiler-introduced stack variables
9679 // (e.g. .result)? For users of the debugger, they will probably be
9680 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009681 Handle<FixedArray> locals =
9682 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009683
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009684 // Fill in the names of the locals.
9685 for (int i = 0; i < info.NumberOfLocals(); i++) {
9686 locals->set(i * 2, *info.LocalName(i));
9687 }
9688
9689 // Fill in the values of the locals.
9690 for (int i = 0; i < info.NumberOfLocals(); i++) {
9691 if (is_optimized_frame) {
9692 // If we are inspecting an optimized frame use undefined as the
9693 // value for all locals.
9694 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009695 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009696 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009697 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009698 } else if (i < info.number_of_stack_slots()) {
9699 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009700 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9701 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009702 // Traverse the context chain to the function context as all local
9703 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009704 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009705 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009706 context = Handle<Context>(context->previous());
9707 }
9708 ASSERT(context->is_function_context());
9709 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009710 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009711 }
9712 }
9713
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009714 // Check whether this frame is positioned at return. If not top
9715 // frame or if the frame is optimized it cannot be at a return.
9716 bool at_return = false;
9717 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009718 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009719 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009720
9721 // If positioned just before return find the value to be returned and add it
9722 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009723 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009724 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009725 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009726 Address internal_frame_sp = NULL;
9727 while (!it2.done()) {
9728 if (it2.frame()->is_internal()) {
9729 internal_frame_sp = it2.frame()->sp();
9730 } else {
9731 if (it2.frame()->is_java_script()) {
9732 if (it2.frame()->id() == it.frame()->id()) {
9733 // The internal frame just before the JavaScript frame contains the
9734 // value to return on top. A debug break at return will create an
9735 // internal frame to store the return value (eax/rax/r0) before
9736 // entering the debug break exit frame.
9737 if (internal_frame_sp != NULL) {
9738 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009739 Handle<Object>(Memory::Object_at(internal_frame_sp),
9740 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009741 break;
9742 }
9743 }
9744 }
9745
9746 // Indicate that the previous frame was not an internal frame.
9747 internal_frame_sp = NULL;
9748 }
9749 it2.Advance();
9750 }
9751 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009752
9753 // Now advance to the arguments adapter frame (if any). It contains all
9754 // the provided parameters whereas the function frame always have the number
9755 // of arguments matching the functions parameters. The rest of the
9756 // information (except for what is collected above) is the same.
9757 it.AdvanceToArgumentsFrame();
9758
9759 // Find the number of arguments to fill. At least fill the number of
9760 // parameters for the function and fill more if more parameters are provided.
9761 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009762 if (argument_count < it.frame()->ComputeParametersCount()) {
9763 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009764 }
9765
9766 // Calculate the size of the result.
9767 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009768 2 * (argument_count + info.NumberOfLocals()) +
9769 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009770 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009771
9772 // Add the frame id.
9773 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9774
9775 // Add the function (same as in function frame).
9776 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9777
9778 // Add the arguments count.
9779 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9780
9781 // Add the locals count
9782 details->set(kFrameDetailsLocalCountIndex,
9783 Smi::FromInt(info.NumberOfLocals()));
9784
9785 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009786 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009787 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9788 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009789 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009790 }
9791
9792 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009793 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009794
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009795 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009796 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009797
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009798 // Add information on whether this frame is invoked in the debugger context.
9799 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009800 heap->ToBoolean(*save->context() ==
9801 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009802
9803 // Fill the dynamic part.
9804 int details_index = kFrameDetailsFirstDynamicIndex;
9805
9806 // Add arguments name and value.
9807 for (int i = 0; i < argument_count; i++) {
9808 // Name of the argument.
9809 if (i < info.number_of_parameters()) {
9810 details->set(details_index++, *info.parameter_name(i));
9811 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009812 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009813 }
9814
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009815 // Parameter value. If we are inspecting an optimized frame, use
9816 // undefined as the value.
9817 //
9818 // TODO(3141533): We should be able to get the actual parameter
9819 // value for optimized frames.
9820 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009821 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009822 details->set(details_index++, it.frame()->GetParameter(i));
9823 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009824 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009825 }
9826 }
9827
9828 // Add locals name and value from the temporary copy from the function frame.
9829 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9830 details->set(details_index++, locals->get(i));
9831 }
9832
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009833 // Add the value being returned.
9834 if (at_return) {
9835 details->set(details_index++, *return_value);
9836 }
9837
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009838 // Add the receiver (same as in function frame).
9839 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9840 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009841 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009842 if (!receiver->IsJSObject()) {
9843 // If the receiver is NOT a JSObject we have hit an optimization
9844 // where a value object is not converted into a wrapped JS objects.
9845 // To hide this optimization from the debugger, we wrap the receiver
9846 // by creating correct wrapper object based on the calling frame's
9847 // global context.
9848 it.Advance();
9849 Handle<Context> calling_frames_global_context(
9850 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009851 receiver =
9852 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009853 }
9854 details->set(kFrameDetailsReceiverIndex, *receiver);
9855
9856 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009857 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009858}
9859
9860
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009861// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009862static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009863 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009864 Handle<SerializedScopeInfo> serialized_scope_info,
9865 ScopeInfo<>& scope_info,
9866 Handle<Context> context,
9867 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009868 // Fill all context locals to the context extension.
9869 for (int i = Context::MIN_CONTEXT_SLOTS;
9870 i < scope_info.number_of_context_slots();
9871 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009872 int context_index = serialized_scope_info->ContextSlotIndex(
9873 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009874
9875 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009876 if (*scope_info.context_slot_name(i) !=
9877 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009878 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009879 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009880 SetProperty(scope_object,
9881 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009882 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009883 NONE,
9884 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009885 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009886 }
9887 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009888
9889 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009890}
9891
9892
9893// Create a plain JSObject which materializes the local scope for the specified
9894// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009895static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9896 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009897 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009898 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009899 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9900 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009901
9902 // Allocate and initialize a JSObject with all the arguments, stack locals
9903 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009904 Handle<JSObject> local_scope =
9905 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009906
9907 // First fill all parameters.
9908 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009909 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009910 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009911 SetProperty(local_scope,
9912 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009913 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009914 NONE,
9915 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009916 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009917 }
9918
9919 // Second fill all stack locals.
9920 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009921 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009922 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009923 SetProperty(local_scope,
9924 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009925 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009926 NONE,
9927 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009928 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009929 }
9930
9931 // Third fill all context locals.
9932 Handle<Context> frame_context(Context::cast(frame->context()));
9933 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009934 if (!CopyContextLocalsToScopeObject(isolate,
9935 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009936 function_context, local_scope)) {
9937 return Handle<JSObject>();
9938 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009939
9940 // Finally copy any properties from the function context extension. This will
9941 // be variables introduced by eval.
9942 if (function_context->closure() == *function) {
9943 if (function_context->has_extension() &&
9944 !function_context->IsGlobalContext()) {
9945 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009946 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009947 for (int i = 0; i < keys->length(); i++) {
9948 // Names of variables introduced by eval are strings.
9949 ASSERT(keys->get(i)->IsString());
9950 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009951 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009952 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009953 SetProperty(local_scope,
9954 key,
9955 GetProperty(ext, key),
9956 NONE,
9957 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009958 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009959 }
9960 }
9961 }
9962 return local_scope;
9963}
9964
9965
9966// Create a plain JSObject which materializes the closure content for the
9967// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009968static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9969 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009970 ASSERT(context->is_function_context());
9971
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009972 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009973 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9974 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009975
9976 // Allocate and initialize a JSObject with all the content of theis function
9977 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009978 Handle<JSObject> closure_scope =
9979 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009980
9981 // Check whether the arguments shadow object exists.
9982 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009983 shared->scope_info()->ContextSlotIndex(
9984 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009985 if (arguments_shadow_index >= 0) {
9986 // In this case all the arguments are available in the arguments shadow
9987 // object.
9988 Handle<JSObject> arguments_shadow(
9989 JSObject::cast(context->get(arguments_shadow_index)));
9990 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009991 // We don't expect exception-throwing getters on the arguments shadow.
9992 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009993 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009994 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009995 SetProperty(closure_scope,
9996 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009997 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009998 NONE,
9999 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010000 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010001 }
10002 }
10003
10004 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010005 if (!CopyContextLocalsToScopeObject(isolate,
10006 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010007 context, closure_scope)) {
10008 return Handle<JSObject>();
10009 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010010
10011 // Finally copy any properties from the function context extension. This will
10012 // be variables introduced by eval.
10013 if (context->has_extension()) {
10014 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010015 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010016 for (int i = 0; i < keys->length(); i++) {
10017 // Names of variables introduced by eval are strings.
10018 ASSERT(keys->get(i)->IsString());
10019 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010020 RETURN_IF_EMPTY_HANDLE_VALUE(
10021 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010022 SetProperty(closure_scope,
10023 key,
10024 GetProperty(ext, key),
10025 NONE,
10026 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010027 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010028 }
10029 }
10030
10031 return closure_scope;
10032}
10033
10034
10035// Iterate over the actual scopes visible from a stack frame. All scopes are
10036// backed by an actual context except the local scope, which is inserted
10037// "artifically" in the context chain.
10038class ScopeIterator {
10039 public:
10040 enum ScopeType {
10041 ScopeTypeGlobal = 0,
10042 ScopeTypeLocal,
10043 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010044 ScopeTypeClosure,
10045 // Every catch block contains an implicit with block (its parameter is
10046 // a JSContextExtensionObject) that extends current scope with a variable
10047 // holding exception object. Such with blocks are treated as scopes of their
10048 // own type.
10049 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010050 };
10051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010052 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10053 : isolate_(isolate),
10054 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010055 function_(JSFunction::cast(frame->function())),
10056 context_(Context::cast(frame->context())),
10057 local_done_(false),
10058 at_local_(false) {
10059
10060 // Check whether the first scope is actually a local scope.
10061 if (context_->IsGlobalContext()) {
10062 // If there is a stack slot for .result then this local scope has been
10063 // created for evaluating top level code and it is not a real local scope.
10064 // Checking for the existence of .result seems fragile, but the scope info
10065 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010066 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010067 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010068 at_local_ = index < 0;
10069 } else if (context_->is_function_context()) {
10070 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010071 } else if (context_->closure() != *function_) {
10072 // The context_ is a with block from the outer function.
10073 ASSERT(context_->has_extension());
10074 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010075 }
10076 }
10077
10078 // More scopes?
10079 bool Done() { return context_.is_null(); }
10080
10081 // Move to the next scope.
10082 void Next() {
10083 // If at a local scope mark the local scope as passed.
10084 if (at_local_) {
10085 at_local_ = false;
10086 local_done_ = true;
10087
10088 // If the current context is not associated with the local scope the
10089 // current context is the next real scope, so don't move to the next
10090 // context in this case.
10091 if (context_->closure() != *function_) {
10092 return;
10093 }
10094 }
10095
10096 // The global scope is always the last in the chain.
10097 if (context_->IsGlobalContext()) {
10098 context_ = Handle<Context>();
10099 return;
10100 }
10101
10102 // Move to the next context.
10103 if (context_->is_function_context()) {
10104 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
10105 } else {
10106 context_ = Handle<Context>(context_->previous());
10107 }
10108
10109 // If passing the local scope indicate that the current scope is now the
10110 // local scope.
10111 if (!local_done_ &&
10112 (context_->IsGlobalContext() || (context_->is_function_context()))) {
10113 at_local_ = true;
10114 }
10115 }
10116
10117 // Return the type of the current scope.
10118 int Type() {
10119 if (at_local_) {
10120 return ScopeTypeLocal;
10121 }
10122 if (context_->IsGlobalContext()) {
10123 ASSERT(context_->global()->IsGlobalObject());
10124 return ScopeTypeGlobal;
10125 }
10126 if (context_->is_function_context()) {
10127 return ScopeTypeClosure;
10128 }
10129 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +000010130 // Current scope is either an explicit with statement or a with statement
10131 // implicitely generated for a catch block.
10132 // If the extension object here is a JSContextExtensionObject then
10133 // current with statement is one frome a catch block otherwise it's a
10134 // regular with statement.
10135 if (context_->extension()->IsJSContextExtensionObject()) {
10136 return ScopeTypeCatch;
10137 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010138 return ScopeTypeWith;
10139 }
10140
10141 // Return the JavaScript object with the content of the current scope.
10142 Handle<JSObject> ScopeObject() {
10143 switch (Type()) {
10144 case ScopeIterator::ScopeTypeGlobal:
10145 return Handle<JSObject>(CurrentContext()->global());
10146 break;
10147 case ScopeIterator::ScopeTypeLocal:
10148 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010149 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010150 break;
10151 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010152 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010153 // Return the with object.
10154 return Handle<JSObject>(CurrentContext()->extension());
10155 break;
10156 case ScopeIterator::ScopeTypeClosure:
10157 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010158 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010159 break;
10160 }
10161 UNREACHABLE();
10162 return Handle<JSObject>();
10163 }
10164
10165 // Return the context for this scope. For the local context there might not
10166 // be an actual context.
10167 Handle<Context> CurrentContext() {
10168 if (at_local_ && context_->closure() != *function_) {
10169 return Handle<Context>();
10170 }
10171 return context_;
10172 }
10173
10174#ifdef DEBUG
10175 // Debug print of the content of the current scope.
10176 void DebugPrint() {
10177 switch (Type()) {
10178 case ScopeIterator::ScopeTypeGlobal:
10179 PrintF("Global:\n");
10180 CurrentContext()->Print();
10181 break;
10182
10183 case ScopeIterator::ScopeTypeLocal: {
10184 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010185 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010186 scope_info.Print();
10187 if (!CurrentContext().is_null()) {
10188 CurrentContext()->Print();
10189 if (CurrentContext()->has_extension()) {
10190 Handle<JSObject> extension =
10191 Handle<JSObject>(CurrentContext()->extension());
10192 if (extension->IsJSContextExtensionObject()) {
10193 extension->Print();
10194 }
10195 }
10196 }
10197 break;
10198 }
10199
10200 case ScopeIterator::ScopeTypeWith: {
10201 PrintF("With:\n");
10202 Handle<JSObject> extension =
10203 Handle<JSObject>(CurrentContext()->extension());
10204 extension->Print();
10205 break;
10206 }
10207
ager@chromium.orga1645e22009-09-09 19:27:10 +000010208 case ScopeIterator::ScopeTypeCatch: {
10209 PrintF("Catch:\n");
10210 Handle<JSObject> extension =
10211 Handle<JSObject>(CurrentContext()->extension());
10212 extension->Print();
10213 break;
10214 }
10215
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010216 case ScopeIterator::ScopeTypeClosure: {
10217 PrintF("Closure:\n");
10218 CurrentContext()->Print();
10219 if (CurrentContext()->has_extension()) {
10220 Handle<JSObject> extension =
10221 Handle<JSObject>(CurrentContext()->extension());
10222 if (extension->IsJSContextExtensionObject()) {
10223 extension->Print();
10224 }
10225 }
10226 break;
10227 }
10228
10229 default:
10230 UNREACHABLE();
10231 }
10232 PrintF("\n");
10233 }
10234#endif
10235
10236 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010237 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010238 JavaScriptFrame* frame_;
10239 Handle<JSFunction> function_;
10240 Handle<Context> context_;
10241 bool local_done_;
10242 bool at_local_;
10243
10244 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10245};
10246
10247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010248RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010249 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010250 ASSERT(args.length() == 2);
10251
10252 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010253 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010254 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10255 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010256 if (!maybe_check->ToObject(&check)) return maybe_check;
10257 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010258 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10259
10260 // Get the frame where the debugging is performed.
10261 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010262 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010263 JavaScriptFrame* frame = it.frame();
10264
10265 // Count the visible scopes.
10266 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010267 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010268 n++;
10269 }
10270
10271 return Smi::FromInt(n);
10272}
10273
10274
10275static const int kScopeDetailsTypeIndex = 0;
10276static const int kScopeDetailsObjectIndex = 1;
10277static const int kScopeDetailsSize = 2;
10278
10279// Return an array with scope details
10280// args[0]: number: break id
10281// args[1]: number: frame index
10282// args[2]: number: scope index
10283//
10284// The array returned contains the following information:
10285// 0: Scope type
10286// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010287RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010288 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010289 ASSERT(args.length() == 3);
10290
10291 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010292 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010293 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10294 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010295 if (!maybe_check->ToObject(&check)) return maybe_check;
10296 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010297 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10298 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10299
10300 // Get the frame where the debugging is performed.
10301 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010302 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010303 JavaScriptFrame* frame = frame_it.frame();
10304
10305 // Find the requested scope.
10306 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010307 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010308 for (; !it.Done() && n < index; it.Next()) {
10309 n++;
10310 }
10311 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010312 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010313 }
10314
10315 // Calculate the size of the result.
10316 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010317 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010318
10319 // Fill in scope details.
10320 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010321 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010322 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010323 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010325 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010326}
10327
10328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010329RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010330 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010331 ASSERT(args.length() == 0);
10332
10333#ifdef DEBUG
10334 // Print the scopes for the top frame.
10335 StackFrameLocator locator;
10336 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010337 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010338 it.DebugPrint();
10339 }
10340#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010341 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010342}
10343
10344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010345RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010346 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010347 ASSERT(args.length() == 1);
10348
10349 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010350 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010351 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10352 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010353 if (!maybe_result->ToObject(&result)) return maybe_result;
10354 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010355
10356 // Count all archived V8 threads.
10357 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010358 for (ThreadState* thread =
10359 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010360 thread != NULL;
10361 thread = thread->Next()) {
10362 n++;
10363 }
10364
10365 // Total number of threads is current thread and archived threads.
10366 return Smi::FromInt(n + 1);
10367}
10368
10369
10370static const int kThreadDetailsCurrentThreadIndex = 0;
10371static const int kThreadDetailsThreadIdIndex = 1;
10372static const int kThreadDetailsSize = 2;
10373
10374// Return an array with thread details
10375// args[0]: number: break id
10376// args[1]: number: thread index
10377//
10378// The array returned contains the following information:
10379// 0: Is current thread?
10380// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010381RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010382 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010383 ASSERT(args.length() == 2);
10384
10385 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010386 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010387 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10388 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010389 if (!maybe_check->ToObject(&check)) return maybe_check;
10390 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010391 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10392
10393 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010394 Handle<FixedArray> details =
10395 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010396
10397 // Thread index 0 is current thread.
10398 if (index == 0) {
10399 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010400 details->set(kThreadDetailsCurrentThreadIndex,
10401 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010402 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010403 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010404 } else {
10405 // Find the thread with the requested index.
10406 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010407 ThreadState* thread =
10408 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010409 while (index != n && thread != NULL) {
10410 thread = thread->Next();
10411 n++;
10412 }
10413 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010414 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010415 }
10416
10417 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010418 details->set(kThreadDetailsCurrentThreadIndex,
10419 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010420 details->set(kThreadDetailsThreadIdIndex,
10421 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010422 }
10423
10424 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010425 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010426}
10427
10428
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010429// Sets the disable break state
10430// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010431RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010432 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010433 ASSERT(args.length() == 1);
10434 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010435 isolate->debug()->set_disable_break(disable_break);
10436 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010437}
10438
10439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010440RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010441 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010442 ASSERT(args.length() == 1);
10443
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010444 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10445 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010446 // Find the number of break points
10447 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010448 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010449 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010450 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010451 Handle<FixedArray>::cast(break_locations));
10452}
10453
10454
10455// Set a break point in a function
10456// args[0]: function
10457// args[1]: number: break source position (within the function source)
10458// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010459RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010460 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010461 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010462 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10463 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010464 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10465 RUNTIME_ASSERT(source_position >= 0);
10466 Handle<Object> break_point_object_arg = args.at<Object>(2);
10467
10468 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010469 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10470 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010471
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010472 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010473}
10474
10475
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010476Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10477 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010478 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010479 // Iterate the heap looking for SharedFunctionInfo generated from the
10480 // script. The inner most SharedFunctionInfo containing the source position
10481 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010482 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010483 // which is found is not compiled it is compiled and the heap is iterated
10484 // again as the compilation might create inner functions from the newly
10485 // compiled function and the actual requested break point might be in one of
10486 // these functions.
10487 bool done = false;
10488 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010489 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010490 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010491 while (!done) {
10492 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010493 for (HeapObject* obj = iterator.next();
10494 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010495 if (obj->IsSharedFunctionInfo()) {
10496 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10497 if (shared->script() == *script) {
10498 // If the SharedFunctionInfo found has the requested script data and
10499 // contains the source position it is a candidate.
10500 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010501 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010502 start_position = shared->start_position();
10503 }
10504 if (start_position <= position &&
10505 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010506 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507 // candidate this is the new candidate.
10508 if (target.is_null()) {
10509 target_start_position = start_position;
10510 target = shared;
10511 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010512 if (target_start_position == start_position &&
10513 shared->end_position() == target->end_position()) {
10514 // If a top-level function contain only one function
10515 // declartion the source for the top-level and the function is
10516 // the same. In that case prefer the non top-level function.
10517 if (!shared->is_toplevel()) {
10518 target_start_position = start_position;
10519 target = shared;
10520 }
10521 } else if (target_start_position <= start_position &&
10522 shared->end_position() <= target->end_position()) {
10523 // This containment check includes equality as a function inside
10524 // a top-level function can share either start or end position
10525 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010526 target_start_position = start_position;
10527 target = shared;
10528 }
10529 }
10530 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010531 }
10532 }
10533 }
10534
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010535 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010536 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010537 }
10538
10539 // If the candidate found is compiled we are done. NOTE: when lazy
10540 // compilation of inner functions is introduced some additional checking
10541 // needs to be done here to compile inner functions.
10542 done = target->is_compiled();
10543 if (!done) {
10544 // If the candidate is not compiled compile it to reveal any inner
10545 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010546 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010547 }
10548 }
10549
10550 return *target;
10551}
10552
10553
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010554// Changes the state of a break point in a script and returns source position
10555// where break point was set. NOTE: Regarding performance see the NOTE for
10556// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010557// args[0]: script to set break point in
10558// args[1]: number: break source position (within the script source)
10559// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010560RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010561 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010562 ASSERT(args.length() == 3);
10563 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10564 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10565 RUNTIME_ASSERT(source_position >= 0);
10566 Handle<Object> break_point_object_arg = args.at<Object>(2);
10567
10568 // Get the script from the script wrapper.
10569 RUNTIME_ASSERT(wrapper->value()->IsScript());
10570 Handle<Script> script(Script::cast(wrapper->value()));
10571
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010572 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010573 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574 if (!result->IsUndefined()) {
10575 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10576 // Find position within function. The script position might be before the
10577 // source position of the first function.
10578 int position;
10579 if (shared->start_position() > source_position) {
10580 position = 0;
10581 } else {
10582 position = source_position - shared->start_position();
10583 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010584 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010585 position += shared->start_position();
10586 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010588 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010589}
10590
10591
10592// Clear a break point
10593// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010594RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010595 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010596 ASSERT(args.length() == 1);
10597 Handle<Object> break_point_object_arg = args.at<Object>(0);
10598
10599 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010600 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010601
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010602 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010603}
10604
10605
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010606// Change the state of break on exceptions.
10607// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10608// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010609RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010610 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010611 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010612 RUNTIME_ASSERT(args[0]->IsNumber());
10613 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010614
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010615 // If the number doesn't match an enum value, the ChangeBreakOnException
10616 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010617 ExceptionBreakType type =
10618 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010619 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010620 isolate->debug()->ChangeBreakOnException(type, enable);
10621 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010622}
10623
10624
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010625// Returns the state of break on exceptions
10626// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010627RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010628 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010629 ASSERT(args.length() == 1);
10630 RUNTIME_ASSERT(args[0]->IsNumber());
10631
10632 ExceptionBreakType type =
10633 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010634 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010635 return Smi::FromInt(result);
10636}
10637
10638
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010639// Prepare for stepping
10640// args[0]: break id for checking execution state
10641// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010642// args[2]: number of times to perform the step, for step out it is the number
10643// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010644RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010645 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010646 ASSERT(args.length() == 3);
10647 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010648 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010649 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10650 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010651 if (!maybe_check->ToObject(&check)) return maybe_check;
10652 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010653 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010654 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010655 }
10656
10657 // Get the step action and check validity.
10658 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10659 if (step_action != StepIn &&
10660 step_action != StepNext &&
10661 step_action != StepOut &&
10662 step_action != StepInMin &&
10663 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010664 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010665 }
10666
10667 // Get the number of steps.
10668 int step_count = NumberToInt32(args[2]);
10669 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010670 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010671 }
10672
ager@chromium.orga1645e22009-09-09 19:27:10 +000010673 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010674 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010675
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010676 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010677 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10678 step_count);
10679 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010680}
10681
10682
10683// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010684RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010685 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010686 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010687 isolate->debug()->ClearStepping();
10688 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010689}
10690
10691
10692// Creates a copy of the with context chain. The copy of the context chain is
10693// is linked to the function context supplied.
10694static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10695 Handle<Context> function_context) {
10696 // At the bottom of the chain. Return the function context to link to.
10697 if (context_chain->is_function_context()) {
10698 return function_context;
10699 }
10700
10701 // Recursively copy the with contexts.
10702 Handle<Context> previous(context_chain->previous());
10703 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
danno@chromium.org160a7b02011-04-18 15:51:38 +000010704 Handle<Context> context = CopyWithContextChain(previous, function_context);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010705 return context->GetIsolate()->factory()->NewWithContext(
10706 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010707}
10708
10709
10710// Helper function to find or create the arguments object for
10711// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010712static Handle<Object> GetArgumentsObject(Isolate* isolate,
10713 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010714 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010715 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010716 const ScopeInfo<>* sinfo,
10717 Handle<Context> function_context) {
10718 // Try to find the value of 'arguments' to pass as parameter. If it is not
10719 // found (that is the debugged function does not reference 'arguments' and
10720 // does not support eval) then create an 'arguments' object.
10721 int index;
10722 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010723 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010724 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010725 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010726 }
10727 }
10728
10729 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010730 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10731 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010732 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010733 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010734 }
10735 }
10736
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010737 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010738 Handle<JSObject> arguments =
10739 isolate->factory()->NewArgumentsObject(function, length);
10740 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010741
10742 AssertNoAllocation no_gc;
10743 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010744 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010745 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010746 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010747 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010748 return arguments;
10749}
10750
10751
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010752static const char kSourceStr[] =
10753 "(function(arguments,__source__){return eval(__source__);})";
10754
10755
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010756// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010757// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010758// extension part has all the parameters and locals of the function on the
10759// stack frame. A function which calls eval with the code to evaluate is then
10760// compiled in this context and called in this context. As this context
10761// replaces the context of the function on the stack frame a new (empty)
10762// function is created as well to be used as the closure for the context.
10763// This function and the context acts as replacements for the function on the
10764// stack frame presenting the same view of the values of parameters and
10765// local variables as if the piece of JavaScript was evaluated at the point
10766// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010767RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010768 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010769
10770 // Check the execution state and decode arguments frame and source to be
10771 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010772 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010773 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010774 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10775 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010776 if (!maybe_check_result->ToObject(&check_result)) {
10777 return maybe_check_result;
10778 }
10779 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010780 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10781 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010782 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010783 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010784
10785 // Handle the processing of break.
10786 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010787
10788 // Get the frame where the debugging is performed.
10789 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010790 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010791 JavaScriptFrame* frame = it.frame();
10792 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010793 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010794 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010795
10796 // Traverse the saved contexts chain to find the active context for the
10797 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010798 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010799 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010800 save = save->prev();
10801 }
10802 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010803 SaveContext savex(isolate);
10804 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010805
10806 // Create the (empty) function replacing the function on the stack frame for
10807 // the purpose of evaluating in the context created below. It is important
10808 // that this function does not describe any parameters and local variables
10809 // in the context. If it does then this will cause problems with the lookup
10810 // in Context::Lookup, where context slots for parameters and local variables
10811 // are looked at before the extension object.
10812 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010813 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10814 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010815 go_between->set_context(function->context());
10816#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010817 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010818 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10819 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10820#endif
10821
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010822 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010823 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10824 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010825
10826 // Allocate a new context for the debug evaluation and set the extension
10827 // object build.
10828 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010829 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10830 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010831 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010832 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010833 Handle<Context> frame_context(Context::cast(frame->context()));
10834 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010835 context = CopyWithContextChain(frame_context, context);
10836
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010837 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010838 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010839 Handle<JSObject>::cast(additional_context), false);
10840 }
10841
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842 // Wrap the evaluation statement in a new function compiled in the newly
10843 // created context. The function has one parameter which has to be called
10844 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010845 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010846 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010847
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010848 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010849 isolate->factory()->NewStringFromAscii(
10850 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010851
10852 // Currently, the eval code will be executed in non-strict mode,
10853 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010854 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010855 Compiler::CompileEval(function_source,
10856 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010857 context->IsGlobalContext(),
10858 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010859 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010860 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010861 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010862
10863 // Invoke the result of the compilation to get the evaluation function.
10864 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010865 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010866 Handle<Object> evaluation_function =
10867 Execution::Call(compiled_function, receiver, 0, NULL,
10868 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010869 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010870
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010871 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10872 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010873 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010874
10875 // Invoke the evaluation function and return the result.
10876 const int argc = 2;
10877 Object** argv[argc] = { arguments.location(),
10878 Handle<Object>::cast(source).location() };
10879 Handle<Object> result =
10880 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10881 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010882 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010883
10884 // Skip the global proxy as it has no properties and always delegates to the
10885 // real global object.
10886 if (result->IsJSGlobalProxy()) {
10887 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10888 }
10889
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890 return *result;
10891}
10892
10893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010894RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010895 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010896
10897 // Check the execution state and decode arguments frame and source to be
10898 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010899 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010900 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010901 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10902 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010903 if (!maybe_check_result->ToObject(&check_result)) {
10904 return maybe_check_result;
10905 }
10906 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010907 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010908 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010909 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010910
10911 // Handle the processing of break.
10912 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010913
10914 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010915 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010916 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010917 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010918 top = top->prev();
10919 }
10920 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010921 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010922 }
10923
10924 // Get the global context now set to the top context from before the
10925 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010926 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010927
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010928 bool is_global = true;
10929
10930 if (additional_context->IsJSObject()) {
10931 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010932 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10933 isolate->factory()->empty_string(),
10934 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010935 go_between->set_context(*context);
10936 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010937 isolate->factory()->NewFunctionContext(
10938 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010939 context->set_extension(JSObject::cast(*additional_context));
10940 is_global = false;
10941 }
10942
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010943 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010944 // Currently, the eval code will be executed in non-strict mode,
10945 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010946 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010947 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010948 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010949 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010950 Handle<JSFunction>(
10951 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10952 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010953
10954 // Invoke the result of the compilation to get the evaluation function.
10955 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010956 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010957 Handle<Object> result =
10958 Execution::Call(compiled_function, receiver, 0, NULL,
10959 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010960 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010961 return *result;
10962}
10963
10964
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010965RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010966 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010967 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010969 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010970 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010971
10972 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010973 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010974 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10975 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10976 // because using
10977 // instances->set(i, *GetScriptWrapper(script))
10978 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10979 // already have deferenced the instances handle.
10980 Handle<JSValue> wrapper = GetScriptWrapper(script);
10981 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010982 }
10983
10984 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010985 Handle<JSObject> result =
10986 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010987 Handle<JSArray>::cast(result)->SetContent(*instances);
10988 return *result;
10989}
10990
10991
10992// Helper function used by Runtime_DebugReferencedBy below.
10993static int DebugReferencedBy(JSObject* target,
10994 Object* instance_filter, int max_references,
10995 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010996 JSFunction* arguments_function) {
10997 NoHandleAllocation ha;
10998 AssertNoAllocation no_alloc;
10999
11000 // Iterate the heap.
11001 int count = 0;
11002 JSObject* last = NULL;
11003 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011004 HeapObject* heap_obj = NULL;
11005 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011006 (max_references == 0 || count < max_references)) {
11007 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011008 if (heap_obj->IsJSObject()) {
11009 // Skip context extension objects and argument arrays as these are
11010 // checked in the context of functions using them.
11011 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011012 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011013 obj->map()->constructor() == arguments_function) {
11014 continue;
11015 }
11016
11017 // Check if the JS object has a reference to the object looked for.
11018 if (obj->ReferencesObject(target)) {
11019 // Check instance filter if supplied. This is normally used to avoid
11020 // references from mirror objects (see Runtime_IsInPrototypeChain).
11021 if (!instance_filter->IsUndefined()) {
11022 Object* V = obj;
11023 while (true) {
11024 Object* prototype = V->GetPrototype();
11025 if (prototype->IsNull()) {
11026 break;
11027 }
11028 if (instance_filter == prototype) {
11029 obj = NULL; // Don't add this object.
11030 break;
11031 }
11032 V = prototype;
11033 }
11034 }
11035
11036 if (obj != NULL) {
11037 // Valid reference found add to instance array if supplied an update
11038 // count.
11039 if (instances != NULL && count < instances_size) {
11040 instances->set(count, obj);
11041 }
11042 last = obj;
11043 count++;
11044 }
11045 }
11046 }
11047 }
11048
11049 // Check for circular reference only. This can happen when the object is only
11050 // referenced from mirrors and has a circular reference in which case the
11051 // object is not really alive and would have been garbage collected if not
11052 // referenced from the mirror.
11053 if (count == 1 && last == target) {
11054 count = 0;
11055 }
11056
11057 // Return the number of referencing objects found.
11058 return count;
11059}
11060
11061
11062// Scan the heap for objects with direct references to an object
11063// args[0]: the object to find references to
11064// args[1]: constructor function for instances to exclude (Mirror)
11065// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011066RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011067 ASSERT(args.length() == 3);
11068
11069 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011070 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011071
11072 // Check parameters.
11073 CONVERT_CHECKED(JSObject, target, args[0]);
11074 Object* instance_filter = args[1];
11075 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11076 instance_filter->IsJSObject());
11077 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11078 RUNTIME_ASSERT(max_references >= 0);
11079
11080 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011081 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011082 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011083 JSFunction* arguments_function =
11084 JSFunction::cast(arguments_boilerplate->map()->constructor());
11085
11086 // Get the number of referencing objects.
11087 int count;
11088 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011089 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011090
11091 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011092 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011093 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011094 if (!maybe_object->ToObject(&object)) return maybe_object;
11095 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011096 FixedArray* instances = FixedArray::cast(object);
11097
11098 // Fill the referencing objects.
11099 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011100 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011101
11102 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011103 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011104 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11105 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011106 if (!maybe_result->ToObject(&result)) return maybe_result;
11107 }
11108 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011109 return result;
11110}
11111
11112
11113// Helper function used by Runtime_DebugConstructedBy below.
11114static int DebugConstructedBy(JSFunction* constructor, int max_references,
11115 FixedArray* instances, int instances_size) {
11116 AssertNoAllocation no_alloc;
11117
11118 // Iterate the heap.
11119 int count = 0;
11120 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011121 HeapObject* heap_obj = NULL;
11122 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011123 (max_references == 0 || count < max_references)) {
11124 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011125 if (heap_obj->IsJSObject()) {
11126 JSObject* obj = JSObject::cast(heap_obj);
11127 if (obj->map()->constructor() == constructor) {
11128 // Valid reference found add to instance array if supplied an update
11129 // count.
11130 if (instances != NULL && count < instances_size) {
11131 instances->set(count, obj);
11132 }
11133 count++;
11134 }
11135 }
11136 }
11137
11138 // Return the number of referencing objects found.
11139 return count;
11140}
11141
11142
11143// Scan the heap for objects constructed by a specific function.
11144// args[0]: the constructor to find instances of
11145// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011146RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011147 ASSERT(args.length() == 2);
11148
11149 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011150 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011151
11152 // Check parameters.
11153 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11154 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11155 RUNTIME_ASSERT(max_references >= 0);
11156
11157 // Get the number of referencing objects.
11158 int count;
11159 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11160
11161 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011162 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011163 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011164 if (!maybe_object->ToObject(&object)) return maybe_object;
11165 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011166 FixedArray* instances = FixedArray::cast(object);
11167
11168 // Fill the referencing objects.
11169 count = DebugConstructedBy(constructor, max_references, instances, count);
11170
11171 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011172 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011173 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11174 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011175 if (!maybe_result->ToObject(&result)) return maybe_result;
11176 }
11177 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011178 return result;
11179}
11180
11181
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011182// Find the effective prototype object as returned by __proto__.
11183// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011184RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011185 ASSERT(args.length() == 1);
11186
11187 CONVERT_CHECKED(JSObject, obj, args[0]);
11188
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011189 // Use the __proto__ accessor.
11190 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011191}
11192
11193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011194RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011195 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011196 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011197 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011198}
11199
11200
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011201RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011202#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011203 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011204 ASSERT(args.length() == 1);
11205 // Get the function and make sure it is compiled.
11206 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011207 Handle<SharedFunctionInfo> shared(func->shared());
11208 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011209 return Failure::Exception();
11210 }
11211 func->code()->PrintLn();
11212#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011213 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011214}
ager@chromium.org9085a012009-05-11 19:22:57 +000011215
11216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011217RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011218#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011219 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011220 ASSERT(args.length() == 1);
11221 // Get the function and make sure it is compiled.
11222 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011223 Handle<SharedFunctionInfo> shared(func->shared());
11224 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011225 return Failure::Exception();
11226 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011227 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011228#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011229 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011230}
11231
11232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011233RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011234 NoHandleAllocation ha;
11235 ASSERT(args.length() == 1);
11236
11237 CONVERT_CHECKED(JSFunction, f, args[0]);
11238 return f->shared()->inferred_name();
11239}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011240
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011241
11242static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011243 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011244 AssertNoAllocation no_allocations;
11245
11246 int counter = 0;
11247 int buffer_size = buffer->length();
11248 HeapIterator iterator;
11249 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11250 ASSERT(obj != NULL);
11251 if (!obj->IsSharedFunctionInfo()) {
11252 continue;
11253 }
11254 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11255 if (shared->script() != script) {
11256 continue;
11257 }
11258 if (counter < buffer_size) {
11259 buffer->set(counter, shared);
11260 }
11261 counter++;
11262 }
11263 return counter;
11264}
11265
11266// For a script finds all SharedFunctionInfo's in the heap that points
11267// to this script. Returns JSArray of SharedFunctionInfo wrapped
11268// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011269RUNTIME_FUNCTION(MaybeObject*,
11270 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011271 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011272 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011273 CONVERT_CHECKED(JSValue, script_value, args[0]);
11274
11275 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11276
11277 const int kBufferSize = 32;
11278
11279 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011280 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011281 int number = FindSharedFunctionInfosForScript(*script, *array);
11282 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011283 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011284 FindSharedFunctionInfosForScript(*script, *array);
11285 }
11286
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011287 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011288 result->set_length(Smi::FromInt(number));
11289
11290 LiveEdit::WrapSharedFunctionInfos(result);
11291
11292 return *result;
11293}
11294
11295// For a script calculates compilation information about all its functions.
11296// The script source is explicitly specified by the second argument.
11297// The source of the actual script is not used, however it is important that
11298// all generated code keeps references to this particular instance of script.
11299// Returns a JSArray of compilation infos. The array is ordered so that
11300// each function with all its descendant is always stored in a continues range
11301// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011302RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011303 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011304 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011305 CONVERT_CHECKED(JSValue, script, args[0]);
11306 CONVERT_ARG_CHECKED(String, source, 1);
11307 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11308
11309 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011311 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011312 return Failure::Exception();
11313 }
11314
11315 return result;
11316}
11317
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011318// Changes the source of the script to a new_source.
11319// If old_script_name is provided (i.e. is a String), also creates a copy of
11320// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011321RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011322 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011323 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011324 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11325 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011326 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011327
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011328 CONVERT_CHECKED(Script, original_script_pointer,
11329 original_script_value->value());
11330 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011331
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011332 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11333 new_source,
11334 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011335
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011336 if (old_script->IsScript()) {
11337 Handle<Script> script_handle(Script::cast(old_script));
11338 return *(GetScriptWrapper(script_handle));
11339 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011340 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011341 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011342}
11343
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011345RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011346 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011347 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011348 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11349 return LiveEdit::FunctionSourceUpdated(shared_info);
11350}
11351
11352
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011353// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011354RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011355 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011356 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011357 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11358 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11359
ager@chromium.orgac091b72010-05-05 07:34:42 +000011360 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011361}
11362
11363// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011364RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011365 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011366 HandleScope scope(isolate);
11367 Handle<Object> function_object(args[0], isolate);
11368 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011369
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011370 if (function_object->IsJSValue()) {
11371 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11372 if (script_object->IsJSValue()) {
11373 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011374 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011375 }
11376
11377 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11378 } else {
11379 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11380 // and we check it in this function.
11381 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011382
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011383 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011384}
11385
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011386
11387// In a code of a parent function replaces original function as embedded object
11388// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011389RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011390 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011391 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011392
11393 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11394 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11395 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11396
11397 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11398 subst_wrapper);
11399
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011400 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011401}
11402
11403
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011404// Updates positions of a shared function info (first parameter) according
11405// to script source change. Text change is described in second parameter as
11406// array of groups of 3 numbers:
11407// (change_begin, change_end, change_end_new_position).
11408// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011409RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011410 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011411 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011412 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11413 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11414
ager@chromium.orgac091b72010-05-05 07:34:42 +000011415 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011416}
11417
11418
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011419// For array of SharedFunctionInfo's (each wrapped in JSValue)
11420// checks that none of them have activations on stacks (of any thread).
11421// Returns array of the same length with corresponding results of
11422// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011423RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011424 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011425 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011426 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011427 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011428
ager@chromium.org357bf652010-04-12 11:30:10 +000011429 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011430}
11431
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011432// Compares 2 strings line-by-line, then token-wise and returns diff in form
11433// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11434// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011435RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011436 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011437 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011438 CONVERT_ARG_CHECKED(String, s1, 0);
11439 CONVERT_ARG_CHECKED(String, s2, 1);
11440
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011441 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011442}
11443
11444
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011445// A testing entry. Returns statement position which is the closest to
11446// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011447RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011448 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011449 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011450 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11451 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11452
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011453 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011454
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011455 if (code->kind() != Code::FUNCTION &&
11456 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011457 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011458 }
11459
11460 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011461 int closest_pc = 0;
11462 int distance = kMaxInt;
11463 while (!it.done()) {
11464 int statement_position = static_cast<int>(it.rinfo()->data());
11465 // Check if this break point is closer that what was previously found.
11466 if (source_position <= statement_position &&
11467 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011468 closest_pc =
11469 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011470 distance = statement_position - source_position;
11471 // Check whether we can't get any closer.
11472 if (distance == 0) break;
11473 }
11474 it.next();
11475 }
11476
11477 return Smi::FromInt(closest_pc);
11478}
11479
11480
ager@chromium.org357bf652010-04-12 11:30:10 +000011481// Calls specified function with or without entering the debugger.
11482// This is used in unit tests to run code as if debugger is entered or simply
11483// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011484RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011485 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011486 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011487 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11488 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11489
11490 Handle<Object> result;
11491 bool pending_exception;
11492 {
11493 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011494 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011495 &pending_exception);
11496 } else {
11497 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011498 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011499 &pending_exception);
11500 }
11501 }
11502 if (!pending_exception) {
11503 return *result;
11504 } else {
11505 return Failure::Exception();
11506 }
11507}
11508
11509
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011510// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011511RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011512 CONVERT_CHECKED(String, arg, args[0]);
11513 SmartPointer<char> flags =
11514 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11515 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011516 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011517}
11518
11519
11520// Performs a GC.
11521// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011522RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011523 isolate->heap()->CollectAllGarbage(true);
11524 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011525}
11526
11527
11528// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011529RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011530 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011531 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011532 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011533 }
11534 return Smi::FromInt(usage);
11535}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011536
11537
11538// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011539RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011540#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011541 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011542#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011543 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011544#endif
11545}
11546
11547
11548// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011549RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011550#ifdef LIVE_OBJECT_LIST
11551 return LiveObjectList::Capture();
11552#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011553 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011554#endif
11555}
11556
11557
11558// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011559RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011560#ifdef LIVE_OBJECT_LIST
11561 CONVERT_SMI_CHECKED(id, args[0]);
11562 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011563 return success ? isolate->heap()->true_value() :
11564 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011565#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011566 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011567#endif
11568}
11569
11570
11571// Generates the response to a debugger request for a dump of the objects
11572// contained in the difference between the captured live object lists
11573// specified by id1 and id2.
11574// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11575// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011576RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011577#ifdef LIVE_OBJECT_LIST
11578 HandleScope scope;
11579 CONVERT_SMI_CHECKED(id1, args[0]);
11580 CONVERT_SMI_CHECKED(id2, args[1]);
11581 CONVERT_SMI_CHECKED(start, args[2]);
11582 CONVERT_SMI_CHECKED(count, args[3]);
11583 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11584 EnterDebugger enter_debugger;
11585 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11586#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011587 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011588#endif
11589}
11590
11591
11592// Gets the specified object as requested by the debugger.
11593// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011594RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011595#ifdef LIVE_OBJECT_LIST
11596 CONVERT_SMI_CHECKED(obj_id, args[0]);
11597 Object* result = LiveObjectList::GetObj(obj_id);
11598 return result;
11599#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011600 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011601#endif
11602}
11603
11604
11605// Gets the obj id for the specified address if valid.
11606// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011607RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011608#ifdef LIVE_OBJECT_LIST
11609 HandleScope scope;
11610 CONVERT_ARG_CHECKED(String, address, 0);
11611 Object* result = LiveObjectList::GetObjId(address);
11612 return result;
11613#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011614 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011615#endif
11616}
11617
11618
11619// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011620RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011621#ifdef LIVE_OBJECT_LIST
11622 HandleScope scope;
11623 CONVERT_SMI_CHECKED(obj_id, args[0]);
11624 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11625 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11626 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11627 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11628 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11629
11630 Handle<JSObject> instance_filter;
11631 if (args[1]->IsJSObject()) {
11632 instance_filter = args.at<JSObject>(1);
11633 }
11634 bool verbose = false;
11635 if (args[2]->IsBoolean()) {
11636 verbose = args[2]->IsTrue();
11637 }
11638 int start = 0;
11639 if (args[3]->IsSmi()) {
11640 start = Smi::cast(args[3])->value();
11641 }
11642 int limit = Smi::kMaxValue;
11643 if (args[4]->IsSmi()) {
11644 limit = Smi::cast(args[4])->value();
11645 }
11646
11647 return LiveObjectList::GetObjRetainers(obj_id,
11648 instance_filter,
11649 verbose,
11650 start,
11651 limit,
11652 filter_obj);
11653#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011654 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011655#endif
11656}
11657
11658
11659// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011660RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011661#ifdef LIVE_OBJECT_LIST
11662 HandleScope scope;
11663 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11664 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11665 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11666
11667 Handle<JSObject> instance_filter;
11668 if (args[2]->IsJSObject()) {
11669 instance_filter = args.at<JSObject>(2);
11670 }
11671
11672 Object* result =
11673 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11674 return result;
11675#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011676 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011677#endif
11678}
11679
11680
11681// Generates the response to a debugger request for a list of all
11682// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011683RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011684#ifdef LIVE_OBJECT_LIST
11685 CONVERT_SMI_CHECKED(start, args[0]);
11686 CONVERT_SMI_CHECKED(count, args[1]);
11687 return LiveObjectList::Info(start, count);
11688#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011689 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011690#endif
11691}
11692
11693
11694// Gets a dump of the specified object as requested by the debugger.
11695// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011696RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011697#ifdef LIVE_OBJECT_LIST
11698 HandleScope scope;
11699 CONVERT_SMI_CHECKED(obj_id, args[0]);
11700 Object* result = LiveObjectList::PrintObj(obj_id);
11701 return result;
11702#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011703 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011704#endif
11705}
11706
11707
11708// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011709RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011710#ifdef LIVE_OBJECT_LIST
11711 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011712 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011713#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011714 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011715#endif
11716}
11717
11718
11719// Generates the response to a debugger request for a summary of the types
11720// of objects in the difference between the captured live object lists
11721// specified by id1 and id2.
11722// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11723// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011724RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011725#ifdef LIVE_OBJECT_LIST
11726 HandleScope scope;
11727 CONVERT_SMI_CHECKED(id1, args[0]);
11728 CONVERT_SMI_CHECKED(id2, args[1]);
11729 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11730
11731 EnterDebugger enter_debugger;
11732 return LiveObjectList::Summarize(id1, id2, filter_obj);
11733#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011734 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011735#endif
11736}
11737
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011738#endif // ENABLE_DEBUGGER_SUPPORT
11739
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011740
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011741#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011742RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011743 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011744 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011745
11746 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011747 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11748 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011749 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011750}
11751
11752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011753RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011754 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011755 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011756
11757 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011758 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11759 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011760 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011761}
11762
11763#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011764
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011765// Finds the script object from the script data. NOTE: This operation uses
11766// heap traversal to find the function generated for the source position
11767// for the requested break point. For lazily compiled functions several heap
11768// traversals might be required rendering this operation as a rather slow
11769// operation. However for setting break points which is normally done through
11770// some kind of user interaction the performance is not crucial.
11771static Handle<Object> Runtime_GetScriptFromScriptName(
11772 Handle<String> script_name) {
11773 // Scan the heap for Script objects to find the script with the requested
11774 // script data.
11775 Handle<Script> script;
11776 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011777 HeapObject* obj = NULL;
11778 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011779 // If a script is found check if it has the script data requested.
11780 if (obj->IsScript()) {
11781 if (Script::cast(obj)->name()->IsString()) {
11782 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11783 script = Handle<Script>(Script::cast(obj));
11784 }
11785 }
11786 }
11787 }
11788
11789 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011790 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011791
11792 // Return the script found.
11793 return GetScriptWrapper(script);
11794}
11795
11796
11797// Get the script object from script data. NOTE: Regarding performance
11798// see the NOTE for GetScriptFromScriptData.
11799// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011800RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011801 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011802
11803 ASSERT(args.length() == 1);
11804
11805 CONVERT_CHECKED(String, script_name, args[0]);
11806
11807 // Find the requested script.
11808 Handle<Object> result =
11809 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11810 return *result;
11811}
11812
11813
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011814// Determines whether the given stack frame should be displayed in
11815// a stack trace. The caller is the error constructor that asked
11816// for the stack trace to be collected. The first time a construct
11817// call to this function is encountered it is skipped. The seen_caller
11818// in/out parameter is used to remember if the caller has been seen
11819// yet.
11820static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11821 bool* seen_caller) {
11822 // Only display JS frames.
11823 if (!raw_frame->is_java_script())
11824 return false;
11825 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11826 Object* raw_fun = frame->function();
11827 // Not sure when this can happen but skip it just in case.
11828 if (!raw_fun->IsJSFunction())
11829 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011830 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011831 *seen_caller = true;
11832 return false;
11833 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011834 // Skip all frames until we've seen the caller. Also, skip the most
11835 // obvious builtin calls. Some builtin calls (such as Number.ADD
11836 // which is invoked using 'call') are very difficult to recognize
11837 // so we're leaving them in for now.
11838 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011839}
11840
11841
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011842// Collect the raw data for a stack trace. Returns an array of 4
11843// element segments each containing a receiver, function, code and
11844// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011845RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011846 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011847 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011848 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11849
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011850 HandleScope scope(isolate);
11851 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011852
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011853 limit = Max(limit, 0); // Ensure that limit is not negative.
11854 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011855 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011856 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011857
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011858 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011859 // If the caller parameter is a function we skip frames until we're
11860 // under it before starting to collect.
11861 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011862 int cursor = 0;
11863 int frames_seen = 0;
11864 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011865 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011866 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011867 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011868 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011869 // Set initial size to the maximum inlining level + 1 for the outermost
11870 // function.
11871 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011872 frame->Summarize(&frames);
11873 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011874 if (cursor + 4 > elements->length()) {
11875 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11876 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011877 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011878 for (int i = 0; i < cursor; i++) {
11879 new_elements->set(i, elements->get(i));
11880 }
11881 elements = new_elements;
11882 }
11883 ASSERT(cursor + 4 <= elements->length());
11884
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011885 Handle<Object> recv = frames[i].receiver();
11886 Handle<JSFunction> fun = frames[i].function();
11887 Handle<Code> code = frames[i].code();
11888 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011889 elements->set(cursor++, *recv);
11890 elements->set(cursor++, *fun);
11891 elements->set(cursor++, *code);
11892 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011893 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011894 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011895 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011896 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011897 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011898 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011899 return *result;
11900}
11901
11902
ager@chromium.org3811b432009-10-28 14:53:37 +000011903// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011904RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011905 ASSERT_EQ(args.length(), 0);
11906
11907 NoHandleAllocation ha;
11908
11909 const char* version_string = v8::V8::GetVersion();
11910
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011911 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11912 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011913}
11914
11915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011916RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011917 ASSERT(args.length() == 2);
11918 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11919 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011920 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011921 OS::Abort();
11922 UNREACHABLE();
11923 return NULL;
11924}
11925
11926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011927RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011928 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011929 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011930 Object* key = args[1];
11931
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011932 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011933 Object* o = cache->get(finger_index);
11934 if (o == key) {
11935 // The fastest case: hit the same place again.
11936 return cache->get(finger_index + 1);
11937 }
11938
11939 for (int i = finger_index - 2;
11940 i >= JSFunctionResultCache::kEntriesIndex;
11941 i -= 2) {
11942 o = cache->get(i);
11943 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011944 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011945 return cache->get(i + 1);
11946 }
11947 }
11948
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011949 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011950 ASSERT(size <= cache->length());
11951
11952 for (int i = size - 2; i > finger_index; i -= 2) {
11953 o = cache->get(i);
11954 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011955 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011956 return cache->get(i + 1);
11957 }
11958 }
11959
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011960 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011961 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011962
11963 Handle<JSFunctionResultCache> cache_handle(cache);
11964 Handle<Object> key_handle(key);
11965 Handle<Object> value;
11966 {
11967 Handle<JSFunction> factory(JSFunction::cast(
11968 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11969 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011970 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011971 // This handle is nor shared, nor used later, so it's safe.
11972 Object** argv[] = { key_handle.location() };
11973 bool pending_exception = false;
11974 value = Execution::Call(factory,
11975 receiver,
11976 1,
11977 argv,
11978 &pending_exception);
11979 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011980 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011981
11982#ifdef DEBUG
11983 cache_handle->JSFunctionResultCacheVerify();
11984#endif
11985
11986 // Function invocation may have cleared the cache. Reread all the data.
11987 finger_index = cache_handle->finger_index();
11988 size = cache_handle->size();
11989
11990 // If we have spare room, put new data into it, otherwise evict post finger
11991 // entry which is likely to be the least recently used.
11992 int index = -1;
11993 if (size < cache_handle->length()) {
11994 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11995 index = size;
11996 } else {
11997 index = finger_index + JSFunctionResultCache::kEntrySize;
11998 if (index == cache_handle->length()) {
11999 index = JSFunctionResultCache::kEntriesIndex;
12000 }
12001 }
12002
12003 ASSERT(index % 2 == 0);
12004 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12005 ASSERT(index < cache_handle->length());
12006
12007 cache_handle->set(index, *key_handle);
12008 cache_handle->set(index + 1, *value);
12009 cache_handle->set_finger_index(index);
12010
12011#ifdef DEBUG
12012 cache_handle->JSFunctionResultCacheVerify();
12013#endif
12014
12015 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012016}
12017
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012019RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012020 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012021 CONVERT_ARG_CHECKED(String, type, 0);
12022 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012023 return *isolate->factory()->NewJSMessageObject(
12024 type,
12025 arguments,
12026 0,
12027 0,
12028 isolate->factory()->undefined_value(),
12029 isolate->factory()->undefined_value(),
12030 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012031}
12032
12033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012034RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012035 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12036 return message->type();
12037}
12038
12039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012040RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012041 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12042 return message->arguments();
12043}
12044
12045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012046RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012047 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12048 return Smi::FromInt(message->start_position());
12049}
12050
12051
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012052RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012053 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12054 return message->script();
12055}
12056
12057
kasper.lund44510672008-07-25 07:37:58 +000012058#ifdef DEBUG
12059// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12060// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012061RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012062 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012063 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012064#define COUNT_ENTRY(Name, argc, ressize) + 1
12065 int entry_count = 0
12066 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12067 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12068 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12069#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012070 Factory* factory = isolate->factory();
12071 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012072 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012073 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012074#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012075 { \
12076 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012077 Handle<String> name; \
12078 /* Inline runtime functions have an underscore in front of the name. */ \
12079 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012080 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012081 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12082 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012083 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012084 Vector<const char>(#Name, StrLength(#Name))); \
12085 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012086 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012087 pair_elements->set(0, *name); \
12088 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012089 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012090 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012091 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012092 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012093 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012094 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012095 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012096 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012097#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012098 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012099 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012100 return *result;
12101}
kasper.lund44510672008-07-25 07:37:58 +000012102#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012103
12104
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012105RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012106 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012107 CONVERT_CHECKED(String, format, args[0]);
12108 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012109 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012110 LOGGER->LogRuntime(chars, elms);
12111 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012112}
12113
12114
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012115RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012116 UNREACHABLE(); // implemented as macro in the parser
12117 return NULL;
12118}
12119
12120
12121// ----------------------------------------------------------------------------
12122// Implementation of Runtime
12123
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012124#define F(name, number_of_args, result_size) \
12125 { Runtime::k##name, Runtime::RUNTIME, #name, \
12126 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012127
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012128
12129#define I(name, number_of_args, result_size) \
12130 { Runtime::kInline##name, Runtime::INLINE, \
12131 "_" #name, NULL, number_of_args, result_size },
12132
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012133static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012134 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012135 INLINE_FUNCTION_LIST(I)
12136 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012137};
12138
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012139
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012140MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12141 Object* dictionary) {
12142 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012143 ASSERT(dictionary != NULL);
12144 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12145 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012146 Object* name_symbol;
12147 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012148 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012149 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12150 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012151 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012152 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12153 String::cast(name_symbol),
12154 Smi::FromInt(i),
12155 PropertyDetails(NONE, NORMAL));
12156 if (!maybe_dictionary->ToObject(&dictionary)) {
12157 // Non-recoverable failure. Calling code must restart heap
12158 // initialization.
12159 return maybe_dictionary;
12160 }
12161 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012162 }
12163 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012164}
12165
12166
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012167const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12168 Heap* heap = name->GetHeap();
12169 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012170 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012171 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012172 int function_index = Smi::cast(smi_index)->value();
12173 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012174 }
12175 return NULL;
12176}
12177
12178
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012179const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012180 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12181}
12182
12183
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012184void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012185 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012186 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012187 if (failure->IsRetryAfterGC()) {
12188 // Try to do a garbage collection; ignore it if it fails. The C
12189 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012190 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012191 } else {
12192 // Handle last resort GC and make sure to allow future allocations
12193 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012194 isolate->counters()->gc_last_resort_from_js()->Increment();
12195 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012196 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012197}
12198
12199
12200} } // namespace v8::internal