blob: 29d4ecd77d5e56ed18710d861c8f4d3ed4b82025 [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"
danno@chromium.org40cb8782011-05-25 07:58:50 +000045#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000046#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000047#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000048#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000051#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000053#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000055#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000056#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
kasperl@chromium.org71affb52009-05-26 05:44:31 +000059namespace v8 {
60namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62
ager@chromium.org3e875802009-06-29 08:26:34 +000063#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000064 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66// Cast the given object to a value of the specified type and store
67// it in a variable with the given name. If the object is not of the
68// expected type call IllegalOperation and return.
69#define CONVERT_CHECKED(Type, name, obj) \
70 RUNTIME_ASSERT(obj->Is##Type()); \
71 Type* name = Type::cast(obj);
72
73#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
75 Handle<Type> name = args.at<Type>(index);
76
kasper.lundbd3ec4e2008-07-09 11:06:54 +000077// Cast the given object to a boolean and store it in a variable with
78// the given name. If the object is not a boolean call IllegalOperation
79// and return.
80#define CONVERT_BOOLEAN_CHECKED(name, obj) \
81 RUNTIME_ASSERT(obj->IsBoolean()); \
82 bool name = (obj)->IsTrue();
83
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000084// Cast the given argument to a Smi and store its value in an int variable
85// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000086// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087#define CONVERT_SMI_ARG_CHECKED(name, index) \
88 RUNTIME_ASSERT(args[index]->IsSmi()); \
89 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000090
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000091// Cast the given argument to a double and store it in a variable with
92// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000093// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
95 RUNTIME_ASSERT(args[index]->IsNumber()); \
96 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097
98// Call the specified converter on the object *comand store the result in
99// a variable of the specified type with the given name. If the
100// object is not a Number call IllegalOperation and return.
101#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
102 RUNTIME_ASSERT(obj->IsNumber()); \
103 type name = NumberTo##Type(obj);
104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000106MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
107 JSObject* boilerplate) {
108 StackLimitCheck check(isolate);
109 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000112 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 if (!maybe_result->ToObject(&result)) return maybe_result;
115 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000116 JSObject* copy = JSObject::cast(result);
117
118 // Deep copy local properties.
119 if (copy->HasFastProperties()) {
120 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000121 for (int i = 0; i < properties->length(); i++) {
122 Object* value = properties->get(i);
123 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000124 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000125 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000126 if (!maybe_result->ToObject(&result)) return maybe_result;
127 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000128 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000129 }
130 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000131 int nof = copy->map()->inobject_properties();
132 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000133 Object* value = copy->InObjectPropertyAt(i);
134 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000135 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000136 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000137 if (!maybe_result->ToObject(&result)) return maybe_result;
138 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000139 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 }
141 }
142 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 if (!maybe_result->ToObject(&result)) return maybe_result;
146 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000147 FixedArray* names = FixedArray::cast(result);
148 copy->GetLocalPropertyNames(names, 0);
149 for (int i = 0; i < names->length(); i++) {
150 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 // Only deep copy fields from the object literal expression.
155 // In particular, don't try to copy the length attribute of
156 // an array.
157 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 Object* value =
159 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000160 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000162 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000163 if (!maybe_result->ToObject(&result)) return maybe_result;
164 }
165 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000166 // Creating object copy for literals. No strict mode needed.
167 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000168 if (!maybe_result->ToObject(&result)) return maybe_result;
169 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000170 }
171 }
172 }
173
174 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000175 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000176 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000177 switch (copy->GetElementsKind()) {
178 case JSObject::FAST_ELEMENTS: {
179 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000180 if (elements->map() == heap->fixed_cow_array_map()) {
181 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000182#ifdef DEBUG
183 for (int i = 0; i < elements->length(); i++) {
184 ASSERT(!elements->get(i)->IsJSObject());
185 }
186#endif
187 } else {
188 for (int i = 0; i < elements->length(); i++) {
189 Object* value = elements->get(i);
190 if (value->IsJSObject()) {
191 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000192 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
193 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000194 if (!maybe_result->ToObject(&result)) return maybe_result;
195 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000196 elements->set(i, result);
197 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000198 }
199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000201 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000202 case JSObject::DICTIONARY_ELEMENTS: {
203 NumberDictionary* element_dictionary = copy->element_dictionary();
204 int capacity = element_dictionary->Capacity();
205 for (int i = 0; i < capacity; i++) {
206 Object* k = element_dictionary->KeyAt(i);
207 if (element_dictionary->IsKey(k)) {
208 Object* value = element_dictionary->ValueAt(i);
209 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000210 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000211 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
212 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000213 if (!maybe_result->ToObject(&result)) return maybe_result;
214 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000215 element_dictionary->ValueAtPut(i, result);
216 }
217 }
218 }
219 break;
220 }
221 default:
222 UNREACHABLE();
223 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 }
225 return copy;
226}
227
228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000229RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000232}
233
234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000235RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238}
239
240
ager@chromium.org236ad962008-09-25 09:45:57 +0000241static Handle<Map> ComputeObjectLiteralMap(
242 Handle<Context> context,
243 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000244 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000245 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000246 int properties_length = constant_properties->length();
247 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000249 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000250 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000251 for (int p = 0; p != properties_length; p += 2) {
252 Object* key = constant_properties->get(p);
253 uint32_t element_index = 0;
254 if (key->IsSymbol()) {
255 number_of_symbol_keys++;
256 } else if (key->ToArrayIndex(&element_index)) {
257 // An index key does not require space in the property backing store.
258 number_of_properties--;
259 } else {
260 // Bail out as a non-symbol non-index key makes caching impossible.
261 // ASSERT to make sure that the if condition after the loop is false.
262 ASSERT(number_of_symbol_keys != number_of_properties);
263 break;
264 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000265 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 // If we only have symbols and array indices among keys then we can
267 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000268 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000269 if ((number_of_symbol_keys == number_of_properties) &&
270 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000271 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000272 Handle<FixedArray> keys =
273 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 if (number_of_symbol_keys > 0) {
275 int index = 0;
276 for (int p = 0; p < properties_length; p += 2) {
277 Object* key = constant_properties->get(p);
278 if (key->IsSymbol()) {
279 keys->set(index++, key);
280 }
281 }
282 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000283 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000284 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000285 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000286 }
287 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000288 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000290 Handle<Map>(context->object_function()->initial_map()),
291 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000292}
293
294
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000296 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000297 Handle<FixedArray> literals,
298 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000300
301static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000303 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000304 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000305 bool should_have_fast_elements,
306 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000307 // Get the global context from the literals array. This is the
308 // context in which the function was created and we use the object
309 // function from this context to create the object literal. We do
310 // not use the object function from the current global context
311 // because this might be the object function from another context
312 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000313 Handle<Context> context =
314 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000316 // In case we have function literals, we want the object to be in
317 // slow properties mode for now. We don't go in the map cache because
318 // maps with constant functions can't be shared if the functions are
319 // not the same (which is the common case).
320 bool is_result_from_cache = false;
321 Handle<Map> map = has_function_literal
322 ? Handle<Map>(context->object_function()->initial_map())
323 : ComputeObjectLiteralMap(context,
324 constant_properties,
325 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000327 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000328
329 // Normalize the elements of the boilerplate to save space if needed.
330 if (!should_have_fast_elements) NormalizeElements(boilerplate);
331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000332 // Add the constant properties to the boilerplate.
333 int length = constant_properties->length();
334 bool should_transform =
335 !is_result_from_cache && boilerplate->HasFastProperties();
336 if (should_transform || has_function_literal) {
337 // Normalize the properties of object to avoid n^2 behavior
338 // when extending the object multiple properties. Indicate the number of
339 // properties to be added.
340 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
341 }
342
343 for (int index = 0; index < length; index +=2) {
344 Handle<Object> key(constant_properties->get(index+0), isolate);
345 Handle<Object> value(constant_properties->get(index+1), isolate);
346 if (value->IsFixedArray()) {
347 // The value contains the constant_properties of a
348 // simple object or array literal.
349 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
350 value = CreateLiteralBoilerplate(isolate, literals, array);
351 if (value.is_null()) return value;
352 }
353 Handle<Object> result;
354 uint32_t element_index = 0;
355 if (key->IsSymbol()) {
356 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
357 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000358 result = SetOwnElement(boilerplate,
359 element_index,
360 value,
361 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000363 Handle<String> name(String::cast(*key));
364 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000365 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
366 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000368 } else if (key->ToArrayIndex(&element_index)) {
369 // Array index (uint32).
370 result = SetOwnElement(boilerplate,
371 element_index,
372 value,
373 kNonStrictMode);
374 } else {
375 // Non-uint32 number.
376 ASSERT(key->IsNumber());
377 double num = key->Number();
378 char arr[100];
379 Vector<char> buffer(arr, ARRAY_SIZE(arr));
380 const char* str = DoubleToCString(num, buffer);
381 Handle<String> name =
382 isolate->factory()->NewStringFromAscii(CStrVector(str));
383 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
384 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000386 // If setting the property on the boilerplate throws an
387 // exception, the exception is converted to an empty handle in
388 // the handle based operations. In that case, we need to
389 // convert back to an exception.
390 if (result.is_null()) return result;
391 }
392
393 // Transform to fast properties if necessary. For object literals with
394 // containing function literals we defer this operation until after all
395 // computed properties have been assigned so that we can generate
396 // constant function properties.
397 if (should_transform && !has_function_literal) {
398 TransformToFastProperties(boilerplate,
399 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 }
401
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000402 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000403}
404
405
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000407 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000408 Handle<FixedArray> literals,
409 Handle<FixedArray> elements) {
410 // Create the JSArray.
411 Handle<JSFunction> constructor(
412 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 const bool is_cow =
416 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000417 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000419
420 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000421 if (is_cow) {
422#ifdef DEBUG
423 // Copy-on-write arrays must be shallow (and simple).
424 for (int i = 0; i < content->length(); i++) {
425 ASSERT(!content->get(i)->IsFixedArray());
426 }
427#endif
428 } else {
429 for (int i = 0; i < content->length(); i++) {
430 if (content->get(i)->IsFixedArray()) {
431 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000433 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
434 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000436 if (result.is_null()) return result;
437 content->set(i, *result);
438 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000439 }
440 }
441
442 // Set the elements.
443 Handle<JSArray>::cast(object)->SetContent(*content);
444 return object;
445}
446
447
448static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000450 Handle<FixedArray> literals,
451 Handle<FixedArray> array) {
452 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000453 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000454 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000455 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000456 return CreateObjectLiteralBoilerplate(isolate,
457 literals,
458 elements,
459 true,
460 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000461 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 return CreateObjectLiteralBoilerplate(isolate,
463 literals,
464 elements,
465 false,
466 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000468 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469 default:
470 UNREACHABLE();
471 return Handle<Object>::null();
472 }
473}
474
475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000476RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000477 // Takes a FixedArray of elements containing the literal elements of
478 // the array literal and produces JSArray with those elements.
479 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000480 // which contains the context from which to get the Array function
481 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000483 ASSERT(args.length() == 3);
484 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000485 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000486 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000488 Handle<Object> object =
489 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000490 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000492 // Update the functions literal and return the boilerplate.
493 literals->set(literals_index, *object);
494 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495}
496
497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000498RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000499 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000500 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000501 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000502 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000503 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000504 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000505 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
506 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000507
508 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000509 Handle<Object> boilerplate(literals->get(literals_index), isolate);
510 if (*boilerplate == isolate->heap()->undefined_value()) {
511 boilerplate = CreateObjectLiteralBoilerplate(isolate,
512 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000513 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000514 should_have_fast_elements,
515 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516 if (boilerplate.is_null()) return Failure::Exception();
517 // Update the functions literal and return the boilerplate.
518 literals->set(literals_index, *boilerplate);
519 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000520 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521}
522
523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000524RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000526 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000527 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000528 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000529 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000530 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000531 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
532 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000533
534 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000535 Handle<Object> boilerplate(literals->get(literals_index), isolate);
536 if (*boilerplate == isolate->heap()->undefined_value()) {
537 boilerplate = CreateObjectLiteralBoilerplate(isolate,
538 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000539 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 should_have_fast_elements,
541 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000542 if (boilerplate.is_null()) return Failure::Exception();
543 // Update the functions literal and return the boilerplate.
544 literals->set(literals_index, *boilerplate);
545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547}
548
549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000550RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 ASSERT(args.length() == 3);
553 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000554 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000555 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
556
557 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 Handle<Object> boilerplate(literals->get(literals_index), isolate);
559 if (*boilerplate == isolate->heap()->undefined_value()) {
560 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000561 if (boilerplate.is_null()) return Failure::Exception();
562 // Update the functions literal and return the boilerplate.
563 literals->set(literals_index, *boilerplate);
564 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000566}
567
568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000569RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000570 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000571 ASSERT(args.length() == 3);
572 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000573 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
575
576 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 Handle<Object> boilerplate(literals->get(literals_index), isolate);
578 if (*boilerplate == isolate->heap()->undefined_value()) {
579 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580 if (boilerplate.is_null()) return Failure::Exception();
581 // Update the functions literal and return the boilerplate.
582 literals->set(literals_index, *boilerplate);
583 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000584 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000585 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000586 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589}
590
591
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000592RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
593 ASSERT(args.length() == 2);
594 Object* handler = args[0];
595 Object* prototype = args[1];
596 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000597 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000598 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
599}
600
601
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000602RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
603 ASSERT(args.length() == 1);
604 Object* obj = args[0];
605 return obj->IsJSProxy()
606 ? isolate->heap()->true_value() : isolate->heap()->false_value();
607}
608
609
610RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
611 ASSERT(args.length() == 1);
612 CONVERT_CHECKED(JSProxy, proxy, args[0]);
613 return proxy->handler();
614}
615
616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000617RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618 NoHandleAllocation ha;
619 ASSERT(args.length() == 1);
620 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000621 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622 return JSObject::cast(obj)->class_name();
623}
624
ager@chromium.org7c537e22008-10-16 08:43:32 +0000625
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000626RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
627 NoHandleAllocation ha;
628 ASSERT(args.length() == 1);
629 Object* obj = args[0];
630 obj = obj->GetPrototype();
631 while (obj->IsJSObject() &&
632 JSObject::cast(obj)->map()->is_hidden_prototype()) {
633 obj = obj->GetPrototype();
634 }
635 return obj;
636}
637
638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
643 Object* O = args[0];
644 Object* V = args[1];
645 while (true) {
646 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 if (prototype->IsNull()) return isolate->heap()->false_value();
648 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 V = prototype;
650 }
651}
652
653
ager@chromium.org9085a012009-05-11 19:22:57 +0000654// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000655RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000656 NoHandleAllocation ha;
657 ASSERT(args.length() == 2);
658 CONVERT_CHECKED(JSObject, jsobject, args[0]);
659 CONVERT_CHECKED(JSObject, proto, args[1]);
660
661 // Sanity checks. The old prototype (that we are replacing) could
662 // theoretically be null, but if it is not null then check that we
663 // didn't already install a hidden prototype here.
664 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
665 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
666 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
667
668 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000669 Object* map_or_failure;
670 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
671 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
672 return maybe_map_or_failure;
673 }
674 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000675 Map* new_proto_map = Map::cast(map_or_failure);
676
lrn@chromium.org303ada72010-10-27 09:33:13 +0000677 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
678 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
679 return maybe_map_or_failure;
680 }
681 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000682 Map* new_map = Map::cast(map_or_failure);
683
684 // Set proto's prototype to be the old prototype of the object.
685 new_proto_map->set_prototype(jsobject->GetPrototype());
686 proto->set_map(new_proto_map);
687 new_proto_map->set_is_hidden_prototype();
688
689 // Set the object's prototype to proto.
690 new_map->set_prototype(proto);
691 jsobject->set_map(new_map);
692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000693 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000694}
695
696
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000697RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000699 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000700 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000701 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702}
703
704
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000705// Recursively traverses hidden prototypes if property is not found
706static void GetOwnPropertyImplementation(JSObject* obj,
707 String* name,
708 LookupResult* result) {
709 obj->LocalLookupRealNamedProperty(name, result);
710
711 if (!result->IsProperty()) {
712 Object* proto = obj->GetPrototype();
713 if (proto->IsJSObject() &&
714 JSObject::cast(proto)->map()->is_hidden_prototype())
715 GetOwnPropertyImplementation(JSObject::cast(proto),
716 name, result);
717 }
718}
719
720
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000721static bool CheckAccessException(LookupResult* result,
722 v8::AccessType access_type) {
723 if (result->type() == CALLBACKS) {
724 Object* callback = result->GetCallbackObject();
725 if (callback->IsAccessorInfo()) {
726 AccessorInfo* info = AccessorInfo::cast(callback);
727 bool can_access =
728 (access_type == v8::ACCESS_HAS &&
729 (info->all_can_read() || info->all_can_write())) ||
730 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
731 (access_type == v8::ACCESS_SET && info->all_can_write());
732 return can_access;
733 }
734 }
735
736 return false;
737}
738
739
740static bool CheckAccess(JSObject* obj,
741 String* name,
742 LookupResult* result,
743 v8::AccessType access_type) {
744 ASSERT(result->IsProperty());
745
746 JSObject* holder = result->holder();
747 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000748 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000749 while (true) {
750 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000751 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000752 // Access check callback denied the access, but some properties
753 // can have a special permissions which override callbacks descision
754 // (currently see v8::AccessControl).
755 break;
756 }
757
758 if (current == holder) {
759 return true;
760 }
761
762 current = JSObject::cast(current->GetPrototype());
763 }
764
765 // API callbacks can have per callback access exceptions.
766 switch (result->type()) {
767 case CALLBACKS: {
768 if (CheckAccessException(result, access_type)) {
769 return true;
770 }
771 break;
772 }
773 case INTERCEPTOR: {
774 // If the object has an interceptor, try real named properties.
775 // Overwrite the result to fetch the correct property later.
776 holder->LookupRealNamedProperty(name, result);
777 if (result->IsProperty()) {
778 if (CheckAccessException(result, access_type)) {
779 return true;
780 }
781 }
782 break;
783 }
784 default:
785 break;
786 }
787
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000788 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000789 return false;
790}
791
792
793// TODO(1095): we should traverse hidden prototype hierachy as well.
794static bool CheckElementAccess(JSObject* obj,
795 uint32_t index,
796 v8::AccessType access_type) {
797 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000798 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000799 return false;
800 }
801
802 return true;
803}
804
805
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000806// Enumerator used as indices into the array returned from GetOwnProperty
807enum PropertyDescriptorIndices {
808 IS_ACCESSOR_INDEX,
809 VALUE_INDEX,
810 GETTER_INDEX,
811 SETTER_INDEX,
812 WRITABLE_INDEX,
813 ENUMERABLE_INDEX,
814 CONFIGURABLE_INDEX,
815 DESCRIPTOR_SIZE
816};
817
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000818// Returns an array with the property description:
819// if args[1] is not a property on args[0]
820// returns undefined
821// if args[1] is a data property on args[0]
822// [false, value, Writeable, Enumerable, Configurable]
823// if args[1] is an accessor on args[0]
824// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000825RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000826 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000827 Heap* heap = isolate->heap();
828 HandleScope scope(isolate);
829 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
830 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000831 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000832 CONVERT_ARG_CHECKED(JSObject, obj, 0);
833 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000834
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000835 // This could be an element.
836 uint32_t index;
837 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000838 switch (obj->HasLocalElement(index)) {
839 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000840 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000841
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000842 case JSObject::STRING_CHARACTER_ELEMENT: {
843 // Special handling of string objects according to ECMAScript 5
844 // 15.5.5.2. Note that this might be a string object with elements
845 // other than the actual string value. This is covered by the
846 // subsequent cases.
847 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
848 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000849 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000851 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000853 elms->set(WRITABLE_INDEX, heap->false_value());
854 elms->set(ENUMERABLE_INDEX, heap->false_value());
855 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000856 return *desc;
857 }
858
859 case JSObject::INTERCEPTED_ELEMENT:
860 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000862 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000863 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000864 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 elms->set(WRITABLE_INDEX, heap->true_value());
866 elms->set(ENUMERABLE_INDEX, heap->true_value());
867 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000868 return *desc;
869 }
870
871 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000872 Handle<JSObject> holder = obj;
873 if (obj->IsJSGlobalProxy()) {
874 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000875 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000876 ASSERT(proto->IsJSGlobalObject());
877 holder = Handle<JSObject>(JSObject::cast(proto));
878 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000879 FixedArray* elements = FixedArray::cast(holder->elements());
880 NumberDictionary* dictionary = NULL;
881 if (elements->map() == heap->non_strict_arguments_elements_map()) {
882 dictionary = NumberDictionary::cast(elements->get(1));
883 } else {
884 dictionary = NumberDictionary::cast(elements);
885 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000886 int entry = dictionary->FindEntry(index);
887 ASSERT(entry != NumberDictionary::kNotFound);
888 PropertyDetails details = dictionary->DetailsAt(entry);
889 switch (details.type()) {
890 case CALLBACKS: {
891 // This is an accessor property with getter and/or setter.
892 FixedArray* callbacks =
893 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000895 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
896 elms->set(GETTER_INDEX, callbacks->get(0));
897 }
898 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
899 elms->set(SETTER_INDEX, callbacks->get(1));
900 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000901 break;
902 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000903 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000904 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000906 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000907 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000908 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000910 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000911 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000912 default:
913 UNREACHABLE();
914 break;
915 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000916 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
917 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000918 return *desc;
919 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000920 }
921 }
922
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000923 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000924 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000925
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000926 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000927 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000928 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000929
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000930 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000932 }
933
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000934 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
935 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000936
937 bool is_js_accessor = (result.type() == CALLBACKS) &&
938 (result.GetCallbackObject()->IsFixedArray());
939
940 if (is_js_accessor) {
941 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000942 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000943
944 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
945 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
946 elms->set(GETTER_INDEX, structure->get(0));
947 }
948 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
949 elms->set(SETTER_INDEX, structure->get(1));
950 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000951 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000952 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
953 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000954
955 PropertyAttributes attrs;
956 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000957 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000958 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
959 if (!maybe_value->ToObject(&value)) return maybe_value;
960 }
961 elms->set(VALUE_INDEX, value);
962 }
963
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000964 return *desc;
965}
966
967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000968RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000969 ASSERT(args.length() == 1);
970 CONVERT_CHECKED(JSObject, obj, args[0]);
971 return obj->PreventExtensions();
972}
973
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000975RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000976 ASSERT(args.length() == 1);
977 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000978 if (obj->IsJSGlobalProxy()) {
979 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000981 ASSERT(proto->IsJSGlobalObject());
982 obj = JSObject::cast(proto);
983 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000984 return obj->map()->is_extensible() ? isolate->heap()->true_value()
985 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000986}
987
988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000989RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000990 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000992 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
993 CONVERT_ARG_CHECKED(String, pattern, 1);
994 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000995 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
996 if (result.is_null()) return Failure::Exception();
997 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998}
999
1000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001001RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001002 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001004 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001005 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006}
1007
1008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001009RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 ASSERT(args.length() == 1);
1011 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001012 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001013 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014}
1015
1016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001017RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018 ASSERT(args.length() == 2);
1019 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001021 int index = field->value();
1022 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1023 InstanceType type = templ->map()->instance_type();
1024 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1025 type == OBJECT_TEMPLATE_INFO_TYPE);
1026 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001027 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001028 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1029 } else {
1030 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1031 }
1032 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001033}
1034
1035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001036RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001037 ASSERT(args.length() == 1);
1038 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001039 Map* old_map = object->map();
1040 bool needs_access_checks = old_map->is_access_check_needed();
1041 if (needs_access_checks) {
1042 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001043 Object* new_map;
1044 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1045 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1046 }
ager@chromium.org32912102009-01-16 10:38:43 +00001047
1048 Map::cast(new_map)->set_is_access_check_needed(false);
1049 object->set_map(Map::cast(new_map));
1050 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001051 return needs_access_checks ? isolate->heap()->true_value()
1052 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001053}
1054
1055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001056RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001057 ASSERT(args.length() == 1);
1058 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001059 Map* old_map = object->map();
1060 if (!old_map->is_access_check_needed()) {
1061 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001062 Object* new_map;
1063 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1064 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1065 }
ager@chromium.org32912102009-01-16 10:38:43 +00001066
1067 Map::cast(new_map)->set_is_access_check_needed(true);
1068 object->set_map(Map::cast(new_map));
1069 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001070 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001071}
1072
1073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001074static Failure* ThrowRedeclarationError(Isolate* isolate,
1075 const char* type,
1076 Handle<String> name) {
1077 HandleScope scope(isolate);
1078 Handle<Object> type_handle =
1079 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080 Handle<Object> args[2] = { type_handle, name };
1081 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001082 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1083 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084}
1085
1086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001087RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001088 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 HandleScope scope(isolate);
1090 Handle<GlobalObject> global = Handle<GlobalObject>(
1091 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001092
ager@chromium.org3811b432009-10-28 14:53:37 +00001093 Handle<Context> context = args.at<Context>(0);
1094 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001095 bool is_eval = args.smi_at(2) == 1;
1096 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001097 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098
1099 // Compute the property attributes. According to ECMA-262, section
1100 // 13, page 71, the property must be read-only and
1101 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1102 // property as read-only, so we don't either.
1103 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001105 // Traverse the name/value pairs and set the properties.
1106 int length = pairs->length();
1107 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001108 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001109 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001110 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111
1112 // We have to declare a global const property. To capture we only
1113 // assign to it when evaluating the assignment for "const x =
1114 // <expr>" the initial value is the hole.
1115 bool is_const_property = value->IsTheHole();
1116
1117 if (value->IsUndefined() || is_const_property) {
1118 // Lookup the property in the global object, and don't set the
1119 // value of the variable if the property is already there.
1120 LookupResult lookup;
1121 global->Lookup(*name, &lookup);
1122 if (lookup.IsProperty()) {
1123 // Determine if the property is local by comparing the holder
1124 // against the global object. The information will be used to
1125 // avoid throwing re-declaration errors when declaring
1126 // variables or constants that exist in the prototype chain.
1127 bool is_local = (*global == lookup.holder());
1128 // Get the property attributes and determine if the property is
1129 // read-only.
1130 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1131 bool is_read_only = (attributes & READ_ONLY) != 0;
1132 if (lookup.type() == INTERCEPTOR) {
1133 // If the interceptor says the property is there, we
1134 // just return undefined without overwriting the property.
1135 // Otherwise, we continue to setting the property.
1136 if (attributes != ABSENT) {
1137 // Check if the existing property conflicts with regards to const.
1138 if (is_local && (is_read_only || is_const_property)) {
1139 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001140 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141 };
1142 // The property already exists without conflicting: Go to
1143 // the next declaration.
1144 continue;
1145 }
1146 // Fall-through and introduce the absent property by using
1147 // SetProperty.
1148 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001149 // For const properties, we treat a callback with this name
1150 // even in the prototype as a conflicting declaration.
1151 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001152 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001153 }
1154 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001155 if (is_local && (is_read_only || is_const_property)) {
1156 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001157 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001158 }
1159 // The property already exists without conflicting: Go to
1160 // the next declaration.
1161 continue;
1162 }
1163 }
1164 } else {
1165 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001166 Handle<SharedFunctionInfo> shared =
1167 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001169 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1170 context,
1171 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172 value = function;
1173 }
1174
1175 LookupResult lookup;
1176 global->LocalLookup(*name, &lookup);
1177
1178 PropertyAttributes attributes = is_const_property
1179 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1180 : base;
1181
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001182 // There's a local property that we need to overwrite because
1183 // we're either declaring a function or there's an interceptor
1184 // that claims the property is absent.
1185 //
1186 // Check for conflicting re-declarations. We cannot have
1187 // conflicting types in case of intercepted properties because
1188 // they are absent.
1189 if (lookup.IsProperty() &&
1190 (lookup.type() != INTERCEPTOR) &&
1191 (lookup.IsReadOnly() || is_const_property)) {
1192 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001193 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001194 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001196 // Safari does not allow the invocation of callback setters for
1197 // function declarations. To mimic this behavior, we do not allow
1198 // the invocation of setters for function values. This makes a
1199 // difference for global functions with the same names as event
1200 // handlers such as "function onload() {}". Firefox does call the
1201 // onload setter in those case and Safari does not. We follow
1202 // Safari for compatibility.
1203 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001204 // Do not change DONT_DELETE to false from true.
1205 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1206 attributes = static_cast<PropertyAttributes>(
1207 attributes | (lookup.GetAttributes() & DONT_DELETE));
1208 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 RETURN_IF_EMPTY_HANDLE(isolate,
1210 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001211 name,
1212 value,
1213 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001215 RETURN_IF_EMPTY_HANDLE(isolate,
1216 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001217 name,
1218 value,
1219 attributes,
1220 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001221 }
1222 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001223
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001224 ASSERT(!isolate->has_pending_exception());
1225 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226}
1227
1228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001229RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001230 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001231 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232
ager@chromium.org7c537e22008-10-16 08:43:32 +00001233 CONVERT_ARG_CHECKED(Context, context, 0);
1234 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001235 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001236 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001237 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001238
1239 // Declarations are always done in the function context.
1240 context = Handle<Context>(context->fcontext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001241 ASSERT(context->IsFunctionContext() || context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001242
1243 int index;
1244 PropertyAttributes attributes;
1245 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001246 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247 context->Lookup(name, flags, &index, &attributes);
1248
1249 if (attributes != ABSENT) {
1250 // The name was declared before; check for conflicting
1251 // re-declarations: This is similar to the code in parser.cc in
1252 // the AstBuildingParser::Declare function.
1253 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1254 // Functions are not read-only.
1255 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1256 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001257 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258 }
1259
1260 // Initialize it if necessary.
1261 if (*initial_value != NULL) {
1262 if (index >= 0) {
1263 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001264 // the function context or the arguments object.
1265 if (holder->IsContext()) {
1266 ASSERT(holder.is_identical_to(context));
1267 if (((attributes & READ_ONLY) == 0) ||
1268 context->get(index)->IsTheHole()) {
1269 context->set(index, *initial_value);
1270 }
1271 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001272 // The holder is an arguments object.
1273 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001274 Handle<Object> result = SetElement(arguments, index, initial_value,
1275 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001276 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 }
1278 } else {
1279 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001280 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001281 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001282 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001283 SetProperty(context_ext, name, initial_value,
1284 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285 }
1286 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001289 // The property is not in the function context. It needs to be
1290 // "declared" in the function context's extension context, or in the
1291 // global context.
1292 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001293 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001294 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001295 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001296 } else {
1297 // The function context's extension context does not exists - allocate
1298 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001299 context_ext = isolate->factory()->NewJSObject(
1300 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001301 // And store it in the extension slot.
1302 context->set_extension(*context_ext);
1303 }
1304 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305
ager@chromium.org7c537e22008-10-16 08:43:32 +00001306 // Declare the property by setting it to the initial value if provided,
1307 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1308 // constant declarations).
1309 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001311 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001312 // Declaring a const context slot is a conflicting declaration if
1313 // there is a callback with that name in a prototype. It is
1314 // allowed to introduce const variables in
1315 // JSContextExtensionObjects. They are treated specially in
1316 // SetProperty and no setters are invoked for those since they are
1317 // not real JSObjects.
1318 if (initial_value->IsTheHole() &&
1319 !context_ext->IsJSContextExtensionObject()) {
1320 LookupResult lookup;
1321 context_ext->Lookup(*name, &lookup);
1322 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001323 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001324 }
1325 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 RETURN_IF_EMPTY_HANDLE(isolate,
1327 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001328 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001329 }
1330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001331 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332}
1333
1334
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001335RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001336 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001337 // args[0] == name
1338 // args[1] == strict_mode
1339 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340
1341 // Determine if we need to assign to the variable if it already
1342 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001343 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1344 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345
1346 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001347 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001348 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001349 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001350 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351
1352 // According to ECMA-262, section 12.2, page 62, the property must
1353 // not be deletable.
1354 PropertyAttributes attributes = DONT_DELETE;
1355
1356 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001357 // there, there is a property with this name in the prototype chain.
1358 // We follow Safari and Firefox behavior and only set the property
1359 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001360 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001361 // Note that objects can have hidden prototypes, so we need to traverse
1362 // the whole chain of hidden prototypes to do a 'local' lookup.
1363 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001365 while (true) {
1366 real_holder->LocalLookup(*name, &lookup);
1367 if (lookup.IsProperty()) {
1368 // Determine if this is a redeclaration of something read-only.
1369 if (lookup.IsReadOnly()) {
1370 // If we found readonly property on one of hidden prototypes,
1371 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001372 if (real_holder != isolate->context()->global()) break;
1373 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001374 }
1375
1376 // Determine if this is a redeclaration of an intercepted read-only
1377 // property and figure out if the property exists at all.
1378 bool found = true;
1379 PropertyType type = lookup.type();
1380 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001381 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001382 Handle<JSObject> holder(real_holder);
1383 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1384 real_holder = *holder;
1385 if (intercepted == ABSENT) {
1386 // The interceptor claims the property isn't there. We need to
1387 // make sure to introduce it.
1388 found = false;
1389 } else if ((intercepted & READ_ONLY) != 0) {
1390 // The property is present, but read-only. Since we're trying to
1391 // overwrite it with a variable declaration we must throw a
1392 // re-declaration error. However if we found readonly property
1393 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001394 if (real_holder != isolate->context()->global()) break;
1395 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001396 }
1397 }
1398
1399 if (found && !assign) {
1400 // The global property is there and we're not assigning any value
1401 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001403 }
1404
1405 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001406 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001407 return real_holder->SetProperty(
1408 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001409 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001410
1411 Object* proto = real_holder->GetPrototype();
1412 if (!proto->IsJSObject())
1413 break;
1414
1415 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1416 break;
1417
1418 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419 }
1420
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001422 if (assign) {
1423 return global->SetProperty(*name, args[2], attributes, strict_mode);
1424 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426}
1427
1428
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001429RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 // All constants are declared with an initial value. The name
1431 // of the constant is the first argument and the initial value
1432 // is the second.
1433 RUNTIME_ASSERT(args.length() == 2);
1434 CONVERT_ARG_CHECKED(String, name, 0);
1435 Handle<Object> value = args.at<Object>(1);
1436
1437 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001438 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439
1440 // According to ECMA-262, section 12.2, page 62, the property must
1441 // not be deletable. Since it's a const, it must be READ_ONLY too.
1442 PropertyAttributes attributes =
1443 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1444
1445 // Lookup the property locally in the global object. If it isn't
1446 // there, we add the property and take special precautions to always
1447 // add it as a local property even in case of callbacks in the
1448 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001449 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450 LookupResult lookup;
1451 global->LocalLookup(*name, &lookup);
1452 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001453 return global->SetLocalPropertyIgnoreAttributes(*name,
1454 *value,
1455 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456 }
1457
1458 // Determine if this is a redeclaration of something not
1459 // read-only. In case the result is hidden behind an interceptor we
1460 // need to ask it for the property attributes.
1461 if (!lookup.IsReadOnly()) {
1462 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001463 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001464 }
1465
1466 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1467
1468 // Throw re-declaration error if the intercepted property is present
1469 // but not read-only.
1470 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 }
1473
1474 // Restore global object from context (in case of GC) and continue
1475 // with setting the value because the property is either absent or
1476 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001477 HandleScope handle_scope(isolate);
1478 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001480 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001481 // property through an interceptor and only do it if it's
1482 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001483 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001484 RETURN_IF_EMPTY_HANDLE(isolate,
1485 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001486 name,
1487 value,
1488 attributes,
1489 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 return *value;
1491 }
1492
1493 // Set the value, but only we're assigning the initial value to a
1494 // constant. For now, we determine this by checking if the
1495 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001496 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497 PropertyType type = lookup.type();
1498 if (type == FIELD) {
1499 FixedArray* properties = global->properties();
1500 int index = lookup.GetFieldIndex();
1501 if (properties->get(index)->IsTheHole()) {
1502 properties->set(index, *value);
1503 }
1504 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001505 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1506 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507 }
1508 } else {
1509 // Ignore re-initialization of constants that have already been
1510 // assigned a function value.
1511 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1512 }
1513
1514 // Use the set value as the result of the operation.
1515 return *value;
1516}
1517
1518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001519RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001520 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521 ASSERT(args.length() == 3);
1522
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001523 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524 ASSERT(!value->IsTheHole());
1525 CONVERT_ARG_CHECKED(Context, context, 1);
1526 Handle<String> name(String::cast(args[2]));
1527
1528 // Initializations are always done in the function context.
1529 context = Handle<Context>(context->fcontext());
1530
1531 int index;
1532 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001533 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001534 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 context->Lookup(name, flags, &index, &attributes);
1536
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001537 // In most situations, the property introduced by the const
1538 // declaration should be present in the context extension object.
1539 // However, because declaration and initialization are separate, the
1540 // property might have been deleted (if it was introduced by eval)
1541 // before we reach the initialization point.
1542 //
1543 // Example:
1544 //
1545 // function f() { eval("delete x; const x;"); }
1546 //
1547 // In that case, the initialization behaves like a normal assignment
1548 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001550 // Property was found in a context.
1551 if (holder->IsContext()) {
1552 // The holder cannot be the function context. If it is, there
1553 // should have been a const redeclaration error when declaring
1554 // the const property.
1555 ASSERT(!holder.is_identical_to(context));
1556 if ((attributes & READ_ONLY) == 0) {
1557 Handle<Context>::cast(holder)->set(index, *value);
1558 }
1559 } else {
1560 // The holder is an arguments object.
1561 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001562 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001563 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001564 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001565 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566 }
1567 return *value;
1568 }
1569
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001570 // The property could not be found, we introduce it in the global
1571 // context.
1572 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001573 Handle<JSObject> global = Handle<JSObject>(
1574 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001575 // Strict mode not needed (const disallowed in strict mode).
1576 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001577 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001578 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001579 return *value;
1580 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001582 // The property was present in a context extension object.
1583 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001584
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001585 if (*context_ext == context->extension()) {
1586 // This is the property that was introduced by the const
1587 // declaration. Set it if it hasn't been set before. NOTE: We
1588 // cannot use GetProperty() to get the current value as it
1589 // 'unholes' the value.
1590 LookupResult lookup;
1591 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1592 ASSERT(lookup.IsProperty()); // the property was declared
1593 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1594
1595 PropertyType type = lookup.type();
1596 if (type == FIELD) {
1597 FixedArray* properties = context_ext->properties();
1598 int index = lookup.GetFieldIndex();
1599 if (properties->get(index)->IsTheHole()) {
1600 properties->set(index, *value);
1601 }
1602 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001603 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1604 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001605 }
1606 } else {
1607 // We should not reach here. Any real, named property should be
1608 // either a field or a dictionary slot.
1609 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001610 }
1611 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001612 // The property was found in a different context extension object.
1613 // Set it if it is not a read-only property.
1614 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001615 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001616 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001617 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001618 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001619 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001621
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001622 return *value;
1623}
1624
1625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001626RUNTIME_FUNCTION(MaybeObject*,
1627 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001628 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001629 ASSERT(args.length() == 2);
1630 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001631 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001632 if (object->HasFastProperties()) {
1633 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1634 }
1635 return *object;
1636}
1637
1638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001639RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001640 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001641 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001642 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1643 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001644 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001645 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001646 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001647 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001648 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001649 RUNTIME_ASSERT(index >= 0);
1650 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001651 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001652 Handle<Object> result = RegExpImpl::Exec(regexp,
1653 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001654 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001655 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001656 if (result.is_null()) return Failure::Exception();
1657 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001658}
1659
1660
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001661RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001662 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001663 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001664 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001665 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001666 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001667 Object* new_object;
1668 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001669 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001670 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1671 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001672 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001673 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1674 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001675 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1676 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001677 {
1678 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001679 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001680 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001682 }
1683 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001685 array->set_elements(elements);
1686 array->set_length(Smi::FromInt(elements_count));
1687 // Write in-object properties after the length of the array.
1688 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1689 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1690 return array;
1691}
1692
1693
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001694RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001695 AssertNoAllocation no_alloc;
1696 ASSERT(args.length() == 5);
1697 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1698 CONVERT_CHECKED(String, source, args[1]);
1699
1700 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001701 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001702
1703 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001704 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001705
1706 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001707 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001708
1709 Map* map = regexp->map();
1710 Object* constructor = map->constructor();
1711 if (constructor->IsJSFunction() &&
1712 JSFunction::cast(constructor)->initial_map() == map) {
1713 // If we still have the original map, set in-object properties directly.
1714 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1715 // TODO(lrn): Consider skipping write barrier on booleans as well.
1716 // Both true and false should be in oldspace at all times.
1717 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1718 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1719 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1720 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1721 Smi::FromInt(0),
1722 SKIP_WRITE_BARRIER);
1723 return regexp;
1724 }
1725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001727 PropertyAttributes final =
1728 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1729 PropertyAttributes writable =
1730 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001732 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001733 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001734 source,
1735 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001736 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001738 global,
1739 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001740 ASSERT(!result->IsFailure());
1741 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001742 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001743 ignoreCase,
1744 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001745 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001747 multiline,
1748 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001749 ASSERT(!result->IsFailure());
1750 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001752 Smi::FromInt(0),
1753 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001754 ASSERT(!result->IsFailure());
1755 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001756 return regexp;
1757}
1758
1759
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001760RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001761 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001762 ASSERT(args.length() == 1);
1763 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1764 // This is necessary to enable fast checks for absence of elements
1765 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001767 return Smi::FromInt(0);
1768}
1769
1770
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001771static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1772 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001773 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001774 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1776 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1777 Handle<JSFunction> optimized =
1778 isolate->factory()->NewFunction(key,
1779 JS_OBJECT_TYPE,
1780 JSObject::kHeaderSize,
1781 code,
1782 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001783 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001784 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001785 return optimized;
1786}
1787
1788
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001789RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001790 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001791 ASSERT(args.length() == 1);
1792 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1793
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001794 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1795 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1796 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1797 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1798 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1799 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1800 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001801
1802 return *holder;
1803}
1804
1805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001806RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001807 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808 Context* global_context =
1809 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001810 return global_context->global()->global_receiver();
1811}
1812
1813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001814RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001815 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816 ASSERT(args.length() == 4);
1817 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001818 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001819 Handle<String> pattern = args.at<String>(2);
1820 Handle<String> flags = args.at<String>(3);
1821
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001822 // Get the RegExp function from the context in the literals array.
1823 // This is the RegExp function from the context in which the
1824 // function was created. We do not use the RegExp function from the
1825 // current global context because this might be the RegExp function
1826 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001827 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001828 Handle<JSFunction>(
1829 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001830 // Compute the regular expression literal.
1831 bool has_pending_exception;
1832 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001833 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1834 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001835 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001837 return Failure::Exception();
1838 }
1839 literals->set(index, *regexp);
1840 return *regexp;
1841}
1842
1843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001844RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001845 NoHandleAllocation ha;
1846 ASSERT(args.length() == 1);
1847
1848 CONVERT_CHECKED(JSFunction, f, args[0]);
1849 return f->shared()->name();
1850}
1851
1852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001853RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001854 NoHandleAllocation ha;
1855 ASSERT(args.length() == 2);
1856
1857 CONVERT_CHECKED(JSFunction, f, args[0]);
1858 CONVERT_CHECKED(String, name, args[1]);
1859 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001860 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001861}
1862
1863
whesse@chromium.org7b260152011-06-20 15:33:18 +00001864RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1865 HandleScope scope(isolate);
1866 ASSERT(args.length() == 1);
1867
1868 CONVERT_CHECKED(JSFunction, fun, args[0]);
1869 fun->shared()->set_bound(true);
1870 return isolate->heap()->undefined_value();
1871}
1872
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001873RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001874 NoHandleAllocation ha;
1875 ASSERT(args.length() == 1);
1876
1877 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001878 Object* obj = f->RemovePrototype();
1879 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001880
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001881 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001882}
1883
1884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001885RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001886 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001887 ASSERT(args.length() == 1);
1888
1889 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001890 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1891 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001892
1893 return *GetScriptWrapper(Handle<Script>::cast(script));
1894}
1895
1896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001897RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001898 NoHandleAllocation ha;
1899 ASSERT(args.length() == 1);
1900
1901 CONVERT_CHECKED(JSFunction, f, args[0]);
1902 return f->shared()->GetSourceCode();
1903}
1904
1905
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001906RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001907 NoHandleAllocation ha;
1908 ASSERT(args.length() == 1);
1909
1910 CONVERT_CHECKED(JSFunction, fun, args[0]);
1911 int pos = fun->shared()->start_position();
1912 return Smi::FromInt(pos);
1913}
1914
1915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001916RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001917 ASSERT(args.length() == 2);
1918
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001919 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001920 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1921
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001922 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1923
1924 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001925 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001926}
1927
1928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001929RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001930 NoHandleAllocation ha;
1931 ASSERT(args.length() == 2);
1932
1933 CONVERT_CHECKED(JSFunction, fun, args[0]);
1934 CONVERT_CHECKED(String, name, args[1]);
1935 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001936 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001937}
1938
1939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001940RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941 NoHandleAllocation ha;
1942 ASSERT(args.length() == 2);
1943
1944 CONVERT_CHECKED(JSFunction, fun, args[0]);
1945 CONVERT_CHECKED(Smi, length, args[1]);
1946 fun->shared()->set_length(length->value());
1947 return length;
1948}
1949
1950
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001951RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001952 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 ASSERT(args.length() == 2);
1954
1955 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001956 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001957 Object* obj;
1958 { MaybeObject* maybe_obj =
1959 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1960 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1961 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 return args[0]; // return TOS
1963}
1964
1965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001966RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001967 NoHandleAllocation ha;
1968 ASSERT(args.length() == 1);
1969
1970 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001971 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1972 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001973}
1974
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001976RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001977 NoHandleAllocation ha;
1978 ASSERT(args.length() == 1);
1979
1980 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001981 return f->IsBuiltin() ? isolate->heap()->true_value() :
1982 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001983}
1984
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001986RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001987 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001988 ASSERT(args.length() == 2);
1989
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001990 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991 Handle<Object> code = args.at<Object>(1);
1992
1993 Handle<Context> context(target->context());
1994
1995 if (!code->IsNull()) {
1996 RUNTIME_ASSERT(code->IsJSFunction());
1997 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001998 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001999
2000 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002001 return Failure::Exception();
2002 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002003 // Since we don't store the source for this we should never
2004 // optimize this.
2005 shared->code()->set_optimizable(false);
2006
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002007 // Set the code, scope info, formal parameter count,
2008 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002009 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002010 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002011 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002012 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002014 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002015 // Set the source code of the target function to undefined.
2016 // SetCode is only used for built-in constructors like String,
2017 // Array, and Object, and some web code
2018 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002019 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002020 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002021 // Clear the optimization hints related to the compiled code as these are no
2022 // longer valid when the code is overwritten.
2023 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002024 context = Handle<Context>(fun->context());
2025
2026 // Make sure we get a fresh copy of the literal vector to avoid
2027 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002028 int number_of_literals = fun->NumberOfLiterals();
2029 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002030 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002031 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002032 // Insert the object, regexp and array functions in the literals
2033 // array prefix. These are the functions that will be used when
2034 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002035 literals->set(JSFunction::kLiteralGlobalContextIndex,
2036 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002037 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002038 // It's okay to skip the write barrier here because the literals
2039 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002040 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002041 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002042 }
2043
2044 target->set_context(*context);
2045 return *target;
2046}
2047
2048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002049RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002051 ASSERT(args.length() == 2);
2052 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002053 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002054 RUNTIME_ASSERT(num >= 0);
2055 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002056 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002057}
2058
2059
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002060MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2061 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002062 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002063 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002064 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002065 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002066 }
2067 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002068 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002069}
2070
2071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002072RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073 NoHandleAllocation ha;
2074 ASSERT(args.length() == 2);
2075
2076 CONVERT_CHECKED(String, subject, args[0]);
2077 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002078 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002079
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002080 uint32_t i = 0;
2081 if (index->IsSmi()) {
2082 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002083 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002084 i = value;
2085 } else {
2086 ASSERT(index->IsHeapNumber());
2087 double value = HeapNumber::cast(index)->value();
2088 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002089 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002090
2091 // Flatten the string. If someone wants to get a char at an index
2092 // in a cons string, it is likely that more indices will be
2093 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002094 Object* flat;
2095 { MaybeObject* maybe_flat = subject->TryFlatten();
2096 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2097 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002098 subject = String::cast(flat);
2099
2100 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002101 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002102 }
2103
2104 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002105}
2106
2107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002108RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002109 NoHandleAllocation ha;
2110 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002111 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002112}
2113
lrn@chromium.org25156de2010-04-06 13:10:27 +00002114
2115class FixedArrayBuilder {
2116 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002117 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2118 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002119 length_(0) {
2120 // Require a non-zero initial size. Ensures that doubling the size to
2121 // extend the array will work.
2122 ASSERT(initial_capacity > 0);
2123 }
2124
2125 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2126 : array_(backing_store),
2127 length_(0) {
2128 // Require a non-zero initial size. Ensures that doubling the size to
2129 // extend the array will work.
2130 ASSERT(backing_store->length() > 0);
2131 }
2132
2133 bool HasCapacity(int elements) {
2134 int length = array_->length();
2135 int required_length = length_ + elements;
2136 return (length >= required_length);
2137 }
2138
2139 void EnsureCapacity(int elements) {
2140 int length = array_->length();
2141 int required_length = length_ + elements;
2142 if (length < required_length) {
2143 int new_length = length;
2144 do {
2145 new_length *= 2;
2146 } while (new_length < required_length);
2147 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002148 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002149 array_->CopyTo(0, *extended_array, 0, length_);
2150 array_ = extended_array;
2151 }
2152 }
2153
2154 void Add(Object* value) {
2155 ASSERT(length_ < capacity());
2156 array_->set(length_, value);
2157 length_++;
2158 }
2159
2160 void Add(Smi* value) {
2161 ASSERT(length_ < capacity());
2162 array_->set(length_, value);
2163 length_++;
2164 }
2165
2166 Handle<FixedArray> array() {
2167 return array_;
2168 }
2169
2170 int length() {
2171 return length_;
2172 }
2173
2174 int capacity() {
2175 return array_->length();
2176 }
2177
2178 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002179 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002180 result_array->set_length(Smi::FromInt(length_));
2181 return result_array;
2182 }
2183
2184 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2185 target_array->set_elements(*array_);
2186 target_array->set_length(Smi::FromInt(length_));
2187 return target_array;
2188 }
2189
2190 private:
2191 Handle<FixedArray> array_;
2192 int length_;
2193};
2194
2195
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002196// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002197const int kStringBuilderConcatHelperLengthBits = 11;
2198const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002199
2200template <typename schar>
2201static inline void StringBuilderConcatHelper(String*,
2202 schar*,
2203 FixedArray*,
2204 int);
2205
lrn@chromium.org25156de2010-04-06 13:10:27 +00002206typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2207 StringBuilderSubstringLength;
2208typedef BitField<int,
2209 kStringBuilderConcatHelperLengthBits,
2210 kStringBuilderConcatHelperPositionBits>
2211 StringBuilderSubstringPosition;
2212
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002213
2214class ReplacementStringBuilder {
2215 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002216 ReplacementStringBuilder(Heap* heap,
2217 Handle<String> subject,
2218 int estimated_part_count)
2219 : heap_(heap),
2220 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002221 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002222 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002223 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002224 // Require a non-zero initial size. Ensures that doubling the size to
2225 // extend the array will work.
2226 ASSERT(estimated_part_count > 0);
2227 }
2228
lrn@chromium.org25156de2010-04-06 13:10:27 +00002229 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2230 int from,
2231 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002232 ASSERT(from >= 0);
2233 int length = to - from;
2234 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002235 if (StringBuilderSubstringLength::is_valid(length) &&
2236 StringBuilderSubstringPosition::is_valid(from)) {
2237 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2238 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002239 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002240 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002241 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002242 builder->Add(Smi::FromInt(-length));
2243 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002244 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002245 }
2246
2247
2248 void EnsureCapacity(int elements) {
2249 array_builder_.EnsureCapacity(elements);
2250 }
2251
2252
2253 void AddSubjectSlice(int from, int to) {
2254 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002255 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002256 }
2257
2258
2259 void AddString(Handle<String> string) {
2260 int length = string->length();
2261 ASSERT(length > 0);
2262 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002263 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002264 is_ascii_ = false;
2265 }
2266 IncrementCharacterCount(length);
2267 }
2268
2269
2270 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002271 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002272 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002273 }
2274
2275 Handle<String> joined_string;
2276 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002277 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002278 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002279 char* char_buffer = seq->GetChars();
2280 StringBuilderConcatHelper(*subject_,
2281 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002282 *array_builder_.array(),
2283 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002284 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002285 } else {
2286 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002287 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002288 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002289 uc16* char_buffer = seq->GetChars();
2290 StringBuilderConcatHelper(*subject_,
2291 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002292 *array_builder_.array(),
2293 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002294 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002295 }
2296 return joined_string;
2297 }
2298
2299
2300 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002301 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002302 V8::FatalProcessOutOfMemory("String.replace result too large.");
2303 }
2304 character_count_ += by;
2305 }
2306
lrn@chromium.org25156de2010-04-06 13:10:27 +00002307 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002308 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002309 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002310
lrn@chromium.org25156de2010-04-06 13:10:27 +00002311 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002312 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2313 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002314 }
2315
2316
ager@chromium.org04921a82011-06-27 13:21:41 +00002317 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2318 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002319 }
2320
2321
2322 void AddElement(Object* element) {
2323 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002324 ASSERT(array_builder_.capacity() > array_builder_.length());
2325 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002326 }
2327
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002328 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002330 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002331 int character_count_;
2332 bool is_ascii_;
2333};
2334
2335
2336class CompiledReplacement {
2337 public:
2338 CompiledReplacement()
2339 : parts_(1), replacement_substrings_(0) {}
2340
2341 void Compile(Handle<String> replacement,
2342 int capture_count,
2343 int subject_length);
2344
2345 void Apply(ReplacementStringBuilder* builder,
2346 int match_from,
2347 int match_to,
2348 Handle<JSArray> last_match_info);
2349
2350 // Number of distinct parts of the replacement pattern.
2351 int parts() {
2352 return parts_.length();
2353 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002354
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002355 private:
2356 enum PartType {
2357 SUBJECT_PREFIX = 1,
2358 SUBJECT_SUFFIX,
2359 SUBJECT_CAPTURE,
2360 REPLACEMENT_SUBSTRING,
2361 REPLACEMENT_STRING,
2362
2363 NUMBER_OF_PART_TYPES
2364 };
2365
2366 struct ReplacementPart {
2367 static inline ReplacementPart SubjectMatch() {
2368 return ReplacementPart(SUBJECT_CAPTURE, 0);
2369 }
2370 static inline ReplacementPart SubjectCapture(int capture_index) {
2371 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2372 }
2373 static inline ReplacementPart SubjectPrefix() {
2374 return ReplacementPart(SUBJECT_PREFIX, 0);
2375 }
2376 static inline ReplacementPart SubjectSuffix(int subject_length) {
2377 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2378 }
2379 static inline ReplacementPart ReplacementString() {
2380 return ReplacementPart(REPLACEMENT_STRING, 0);
2381 }
2382 static inline ReplacementPart ReplacementSubString(int from, int to) {
2383 ASSERT(from >= 0);
2384 ASSERT(to > from);
2385 return ReplacementPart(-from, to);
2386 }
2387
2388 // If tag <= 0 then it is the negation of a start index of a substring of
2389 // the replacement pattern, otherwise it's a value from PartType.
2390 ReplacementPart(int tag, int data)
2391 : tag(tag), data(data) {
2392 // Must be non-positive or a PartType value.
2393 ASSERT(tag < NUMBER_OF_PART_TYPES);
2394 }
2395 // Either a value of PartType or a non-positive number that is
2396 // the negation of an index into the replacement string.
2397 int tag;
2398 // The data value's interpretation depends on the value of tag:
2399 // tag == SUBJECT_PREFIX ||
2400 // tag == SUBJECT_SUFFIX: data is unused.
2401 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2402 // tag == REPLACEMENT_SUBSTRING ||
2403 // tag == REPLACEMENT_STRING: data is index into array of substrings
2404 // of the replacement string.
2405 // tag <= 0: Temporary representation of the substring of the replacement
2406 // string ranging over -tag .. data.
2407 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2408 // substring objects.
2409 int data;
2410 };
2411
2412 template<typename Char>
2413 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2414 Vector<Char> characters,
2415 int capture_count,
2416 int subject_length) {
2417 int length = characters.length();
2418 int last = 0;
2419 for (int i = 0; i < length; i++) {
2420 Char c = characters[i];
2421 if (c == '$') {
2422 int next_index = i + 1;
2423 if (next_index == length) { // No next character!
2424 break;
2425 }
2426 Char c2 = characters[next_index];
2427 switch (c2) {
2428 case '$':
2429 if (i > last) {
2430 // There is a substring before. Include the first "$".
2431 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2432 last = next_index + 1; // Continue after the second "$".
2433 } else {
2434 // Let the next substring start with the second "$".
2435 last = next_index;
2436 }
2437 i = next_index;
2438 break;
2439 case '`':
2440 if (i > last) {
2441 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2442 }
2443 parts->Add(ReplacementPart::SubjectPrefix());
2444 i = next_index;
2445 last = i + 1;
2446 break;
2447 case '\'':
2448 if (i > last) {
2449 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2450 }
2451 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2452 i = next_index;
2453 last = i + 1;
2454 break;
2455 case '&':
2456 if (i > last) {
2457 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2458 }
2459 parts->Add(ReplacementPart::SubjectMatch());
2460 i = next_index;
2461 last = i + 1;
2462 break;
2463 case '0':
2464 case '1':
2465 case '2':
2466 case '3':
2467 case '4':
2468 case '5':
2469 case '6':
2470 case '7':
2471 case '8':
2472 case '9': {
2473 int capture_ref = c2 - '0';
2474 if (capture_ref > capture_count) {
2475 i = next_index;
2476 continue;
2477 }
2478 int second_digit_index = next_index + 1;
2479 if (second_digit_index < length) {
2480 // Peek ahead to see if we have two digits.
2481 Char c3 = characters[second_digit_index];
2482 if ('0' <= c3 && c3 <= '9') { // Double digits.
2483 int double_digit_ref = capture_ref * 10 + c3 - '0';
2484 if (double_digit_ref <= capture_count) {
2485 next_index = second_digit_index;
2486 capture_ref = double_digit_ref;
2487 }
2488 }
2489 }
2490 if (capture_ref > 0) {
2491 if (i > last) {
2492 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2493 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002494 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002495 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2496 last = next_index + 1;
2497 }
2498 i = next_index;
2499 break;
2500 }
2501 default:
2502 i = next_index;
2503 break;
2504 }
2505 }
2506 }
2507 if (length > last) {
2508 if (last == 0) {
2509 parts->Add(ReplacementPart::ReplacementString());
2510 } else {
2511 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2512 }
2513 }
2514 }
2515
2516 ZoneList<ReplacementPart> parts_;
2517 ZoneList<Handle<String> > replacement_substrings_;
2518};
2519
2520
2521void CompiledReplacement::Compile(Handle<String> replacement,
2522 int capture_count,
2523 int subject_length) {
2524 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002525 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002526 AssertNoAllocation no_alloc;
2527 ParseReplacementPattern(&parts_,
2528 replacement->ToAsciiVector(),
2529 capture_count,
2530 subject_length);
2531 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002532 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002533 AssertNoAllocation no_alloc;
2534
2535 ParseReplacementPattern(&parts_,
2536 replacement->ToUC16Vector(),
2537 capture_count,
2538 subject_length);
2539 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002540 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002541 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002542 int substring_index = 0;
2543 for (int i = 0, n = parts_.length(); i < n; i++) {
2544 int tag = parts_[i].tag;
2545 if (tag <= 0) { // A replacement string slice.
2546 int from = -tag;
2547 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002548 replacement_substrings_.Add(
2549 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002550 parts_[i].tag = REPLACEMENT_SUBSTRING;
2551 parts_[i].data = substring_index;
2552 substring_index++;
2553 } else if (tag == REPLACEMENT_STRING) {
2554 replacement_substrings_.Add(replacement);
2555 parts_[i].data = substring_index;
2556 substring_index++;
2557 }
2558 }
2559}
2560
2561
2562void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2563 int match_from,
2564 int match_to,
2565 Handle<JSArray> last_match_info) {
2566 for (int i = 0, n = parts_.length(); i < n; i++) {
2567 ReplacementPart part = parts_[i];
2568 switch (part.tag) {
2569 case SUBJECT_PREFIX:
2570 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2571 break;
2572 case SUBJECT_SUFFIX: {
2573 int subject_length = part.data;
2574 if (match_to < subject_length) {
2575 builder->AddSubjectSlice(match_to, subject_length);
2576 }
2577 break;
2578 }
2579 case SUBJECT_CAPTURE: {
2580 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002581 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002582 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2583 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2584 if (from >= 0 && to > from) {
2585 builder->AddSubjectSlice(from, to);
2586 }
2587 break;
2588 }
2589 case REPLACEMENT_SUBSTRING:
2590 case REPLACEMENT_STRING:
2591 builder->AddString(replacement_substrings_[part.data]);
2592 break;
2593 default:
2594 UNREACHABLE();
2595 }
2596 }
2597}
2598
2599
2600
lrn@chromium.org303ada72010-10-27 09:33:13 +00002601MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002602 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002603 String* subject,
2604 JSRegExp* regexp,
2605 String* replacement,
2606 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002607 ASSERT(subject->IsFlat());
2608 ASSERT(replacement->IsFlat());
2609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002610 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002611
2612 int length = subject->length();
2613 Handle<String> subject_handle(subject);
2614 Handle<JSRegExp> regexp_handle(regexp);
2615 Handle<String> replacement_handle(replacement);
2616 Handle<JSArray> last_match_info_handle(last_match_info);
2617 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2618 subject_handle,
2619 0,
2620 last_match_info_handle);
2621 if (match.is_null()) {
2622 return Failure::Exception();
2623 }
2624 if (match->IsNull()) {
2625 return *subject_handle;
2626 }
2627
2628 int capture_count = regexp_handle->CaptureCount();
2629
2630 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002631 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002632 CompiledReplacement compiled_replacement;
2633 compiled_replacement.Compile(replacement_handle,
2634 capture_count,
2635 length);
2636
2637 bool is_global = regexp_handle->GetFlags().is_global();
2638
2639 // Guessing the number of parts that the final result string is built
2640 // from. Global regexps can match any number of times, so we guess
2641 // conservatively.
2642 int expected_parts =
2643 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002644 ReplacementStringBuilder builder(isolate->heap(),
2645 subject_handle,
2646 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002647
2648 // Index of end of last match.
2649 int prev = 0;
2650
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002651 // Number of parts added by compiled replacement plus preceeding
2652 // string and possibly suffix after last match. It is possible for
2653 // all components to use two elements when encoded as two smis.
2654 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002655 bool matched = true;
2656 do {
2657 ASSERT(last_match_info_handle->HasFastElements());
2658 // Increase the capacity of the builder before entering local handle-scope,
2659 // so its internal buffer can safely allocate a new handle if it grows.
2660 builder.EnsureCapacity(parts_added_per_loop);
2661
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002662 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002663 int start, end;
2664 {
2665 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002666 FixedArray* match_info_array =
2667 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002668
2669 ASSERT_EQ(capture_count * 2 + 2,
2670 RegExpImpl::GetLastCaptureCount(match_info_array));
2671 start = RegExpImpl::GetCapture(match_info_array, 0);
2672 end = RegExpImpl::GetCapture(match_info_array, 1);
2673 }
2674
2675 if (prev < start) {
2676 builder.AddSubjectSlice(prev, start);
2677 }
2678 compiled_replacement.Apply(&builder,
2679 start,
2680 end,
2681 last_match_info_handle);
2682 prev = end;
2683
2684 // Only continue checking for global regexps.
2685 if (!is_global) break;
2686
2687 // Continue from where the match ended, unless it was an empty match.
2688 int next = end;
2689 if (start == end) {
2690 next = end + 1;
2691 if (next > length) break;
2692 }
2693
2694 match = RegExpImpl::Exec(regexp_handle,
2695 subject_handle,
2696 next,
2697 last_match_info_handle);
2698 if (match.is_null()) {
2699 return Failure::Exception();
2700 }
2701 matched = !match->IsNull();
2702 } while (matched);
2703
2704 if (prev < length) {
2705 builder.AddSubjectSlice(prev, length);
2706 }
2707
2708 return *(builder.ToString());
2709}
2710
2711
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002712template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002713MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002714 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002715 String* subject,
2716 JSRegExp* regexp,
2717 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002718 ASSERT(subject->IsFlat());
2719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002720 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002721
2722 Handle<String> subject_handle(subject);
2723 Handle<JSRegExp> regexp_handle(regexp);
2724 Handle<JSArray> last_match_info_handle(last_match_info);
2725 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2726 subject_handle,
2727 0,
2728 last_match_info_handle);
2729 if (match.is_null()) return Failure::Exception();
2730 if (match->IsNull()) return *subject_handle;
2731
2732 ASSERT(last_match_info_handle->HasFastElements());
2733
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002734 int start, end;
2735 {
2736 AssertNoAllocation match_info_array_is_not_in_a_handle;
2737 FixedArray* match_info_array =
2738 FixedArray::cast(last_match_info_handle->elements());
2739
2740 start = RegExpImpl::GetCapture(match_info_array, 0);
2741 end = RegExpImpl::GetCapture(match_info_array, 1);
2742 }
2743
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002744 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002745 int new_length = length - (end - start);
2746 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002747 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002748 }
2749 Handle<ResultSeqString> answer;
2750 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002751 answer = Handle<ResultSeqString>::cast(
2752 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002753 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002754 answer = Handle<ResultSeqString>::cast(
2755 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002756 }
2757
2758 // If the regexp isn't global, only match once.
2759 if (!regexp_handle->GetFlags().is_global()) {
2760 if (start > 0) {
2761 String::WriteToFlat(*subject_handle,
2762 answer->GetChars(),
2763 0,
2764 start);
2765 }
2766 if (end < length) {
2767 String::WriteToFlat(*subject_handle,
2768 answer->GetChars() + start,
2769 end,
2770 length);
2771 }
2772 return *answer;
2773 }
2774
2775 int prev = 0; // Index of end of last match.
2776 int next = 0; // Start of next search (prev unless last match was empty).
2777 int position = 0;
2778
2779 do {
2780 if (prev < start) {
2781 // Add substring subject[prev;start] to answer string.
2782 String::WriteToFlat(*subject_handle,
2783 answer->GetChars() + position,
2784 prev,
2785 start);
2786 position += start - prev;
2787 }
2788 prev = end;
2789 next = end;
2790 // Continue from where the match ended, unless it was an empty match.
2791 if (start == end) {
2792 next++;
2793 if (next > length) break;
2794 }
2795 match = RegExpImpl::Exec(regexp_handle,
2796 subject_handle,
2797 next,
2798 last_match_info_handle);
2799 if (match.is_null()) return Failure::Exception();
2800 if (match->IsNull()) break;
2801
2802 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002803 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002804 {
2805 AssertNoAllocation match_info_array_is_not_in_a_handle;
2806 FixedArray* match_info_array =
2807 FixedArray::cast(last_match_info_handle->elements());
2808 start = RegExpImpl::GetCapture(match_info_array, 0);
2809 end = RegExpImpl::GetCapture(match_info_array, 1);
2810 }
2811 } while (true);
2812
2813 if (prev < length) {
2814 // Add substring subject[prev;length] to answer string.
2815 String::WriteToFlat(*subject_handle,
2816 answer->GetChars() + position,
2817 prev,
2818 length);
2819 position += length - prev;
2820 }
2821
2822 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002823 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002824 }
2825
2826 // Shorten string and fill
2827 int string_size = ResultSeqString::SizeFor(position);
2828 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2829 int delta = allocated_string_size - string_size;
2830
2831 answer->set_length(position);
2832 if (delta == 0) return *answer;
2833
2834 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002835 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002836
2837 return *answer;
2838}
2839
2840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002841RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002842 ASSERT(args.length() == 4);
2843
2844 CONVERT_CHECKED(String, subject, args[0]);
2845 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002846 Object* flat_subject;
2847 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2848 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2849 return maybe_flat_subject;
2850 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002851 }
2852 subject = String::cast(flat_subject);
2853 }
2854
2855 CONVERT_CHECKED(String, replacement, args[2]);
2856 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002857 Object* flat_replacement;
2858 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2859 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2860 return maybe_flat_replacement;
2861 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002862 }
2863 replacement = String::cast(flat_replacement);
2864 }
2865
2866 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2867 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2868
2869 ASSERT(last_match_info->HasFastElements());
2870
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002871 if (replacement->length() == 0) {
2872 if (subject->HasOnlyAsciiChars()) {
2873 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002874 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002875 } else {
2876 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002877 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002878 }
2879 }
2880
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002881 return StringReplaceRegExpWithString(isolate,
2882 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002883 regexp,
2884 replacement,
2885 last_match_info);
2886}
2887
2888
ager@chromium.org7c537e22008-10-16 08:43:32 +00002889// Perform string match of pattern on subject, starting at start index.
2890// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002891// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002892int Runtime::StringMatch(Isolate* isolate,
2893 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002894 Handle<String> pat,
2895 int start_index) {
2896 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002897 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002898
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002899 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002900 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002901
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002902 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002903 if (start_index + pattern_length > subject_length) return -1;
2904
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002905 if (!sub->IsFlat()) FlattenString(sub);
2906 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002907
ager@chromium.org7c537e22008-10-16 08:43:32 +00002908 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002909 // Extract flattened substrings of cons strings before determining asciiness.
2910 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002911 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002912 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002913 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002914
ager@chromium.org7c537e22008-10-16 08:43:32 +00002915 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002916 if (seq_pat->IsAsciiRepresentation()) {
2917 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2918 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002919 return SearchString(isolate,
2920 seq_sub->ToAsciiVector(),
2921 pat_vector,
2922 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002923 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002924 return SearchString(isolate,
2925 seq_sub->ToUC16Vector(),
2926 pat_vector,
2927 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002928 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002929 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2930 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002931 return SearchString(isolate,
2932 seq_sub->ToAsciiVector(),
2933 pat_vector,
2934 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002935 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002936 return SearchString(isolate,
2937 seq_sub->ToUC16Vector(),
2938 pat_vector,
2939 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002940}
2941
2942
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002943RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002944 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002945 ASSERT(args.length() == 3);
2946
ager@chromium.org7c537e22008-10-16 08:43:32 +00002947 CONVERT_ARG_CHECKED(String, sub, 0);
2948 CONVERT_ARG_CHECKED(String, pat, 1);
2949
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002950 Object* index = args[2];
2951 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002952 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002953
ager@chromium.org870a0b62008-11-04 11:43:05 +00002954 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002955 int position =
2956 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002957 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002958}
2959
2960
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002961template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002962static int StringMatchBackwards(Vector<const schar> subject,
2963 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002964 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002965 int pattern_length = pattern.length();
2966 ASSERT(pattern_length >= 1);
2967 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002968
2969 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002970 for (int i = 0; i < pattern_length; i++) {
2971 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002972 if (c > String::kMaxAsciiCharCode) {
2973 return -1;
2974 }
2975 }
2976 }
2977
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002978 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002979 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002980 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002981 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002982 while (j < pattern_length) {
2983 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002984 break;
2985 }
2986 j++;
2987 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002988 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002989 return i;
2990 }
2991 }
2992 return -1;
2993}
2994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002995RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002996 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002997 ASSERT(args.length() == 3);
2998
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002999 CONVERT_ARG_CHECKED(String, sub, 0);
3000 CONVERT_ARG_CHECKED(String, pat, 1);
3001
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003002 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003003 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003004 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003005
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003006 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003007 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003008
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003009 if (start_index + pat_length > sub_length) {
3010 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003011 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003012
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003013 if (pat_length == 0) {
3014 return Smi::FromInt(start_index);
3015 }
3016
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003017 if (!sub->IsFlat()) FlattenString(sub);
3018 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003019
3020 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3021
3022 int position = -1;
3023
3024 if (pat->IsAsciiRepresentation()) {
3025 Vector<const char> pat_vector = pat->ToAsciiVector();
3026 if (sub->IsAsciiRepresentation()) {
3027 position = StringMatchBackwards(sub->ToAsciiVector(),
3028 pat_vector,
3029 start_index);
3030 } else {
3031 position = StringMatchBackwards(sub->ToUC16Vector(),
3032 pat_vector,
3033 start_index);
3034 }
3035 } else {
3036 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3037 if (sub->IsAsciiRepresentation()) {
3038 position = StringMatchBackwards(sub->ToAsciiVector(),
3039 pat_vector,
3040 start_index);
3041 } else {
3042 position = StringMatchBackwards(sub->ToUC16Vector(),
3043 pat_vector,
3044 start_index);
3045 }
3046 }
3047
3048 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003049}
3050
3051
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003052RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003053 NoHandleAllocation ha;
3054 ASSERT(args.length() == 2);
3055
3056 CONVERT_CHECKED(String, str1, args[0]);
3057 CONVERT_CHECKED(String, str2, args[1]);
3058
3059 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003060 int str1_length = str1->length();
3061 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003062
3063 // Decide trivial cases without flattening.
3064 if (str1_length == 0) {
3065 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3066 return Smi::FromInt(-str2_length);
3067 } else {
3068 if (str2_length == 0) return Smi::FromInt(str1_length);
3069 }
3070
3071 int end = str1_length < str2_length ? str1_length : str2_length;
3072
3073 // No need to flatten if we are going to find the answer on the first
3074 // character. At this point we know there is at least one character
3075 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003076 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003077 if (d != 0) return Smi::FromInt(d);
3078
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003079 str1->TryFlatten();
3080 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003081
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003082 StringInputBuffer& buf1 =
3083 *isolate->runtime_state()->string_locale_compare_buf1();
3084 StringInputBuffer& buf2 =
3085 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003086
3087 buf1.Reset(str1);
3088 buf2.Reset(str2);
3089
3090 for (int i = 0; i < end; i++) {
3091 uint16_t char1 = buf1.GetNext();
3092 uint16_t char2 = buf2.GetNext();
3093 if (char1 != char2) return Smi::FromInt(char1 - char2);
3094 }
3095
3096 return Smi::FromInt(str1_length - str2_length);
3097}
3098
3099
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003100RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003101 NoHandleAllocation ha;
3102 ASSERT(args.length() == 3);
3103
3104 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003105 int start, end;
3106 // We have a fast integer-only case here to avoid a conversion to double in
3107 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003108 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3109 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3110 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3111 start = from_number;
3112 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003113 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003114 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3115 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003116 start = FastD2I(from_number);
3117 end = FastD2I(to_number);
3118 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003119 RUNTIME_ASSERT(end >= start);
3120 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003121 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003122 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003123 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003124}
3125
3126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003127RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003128 ASSERT_EQ(3, args.length());
3129
3130 CONVERT_ARG_CHECKED(String, subject, 0);
3131 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3132 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3133 HandleScope handles;
3134
3135 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3136
3137 if (match.is_null()) {
3138 return Failure::Exception();
3139 }
3140 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003141 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003142 }
3143 int length = subject->length();
3144
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003145 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003146 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003147 int start;
3148 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003149 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003150 {
3151 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003152 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003153 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3154 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3155 }
3156 offsets.Add(start);
3157 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003158 if (start == end) if (++end > length) break;
3159 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003160 if (match.is_null()) {
3161 return Failure::Exception();
3162 }
3163 } while (!match->IsNull());
3164 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003165 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003166 Handle<String> substring = isolate->factory()->
3167 NewSubString(subject, offsets.at(0), offsets.at(1));
3168 elements->set(0, *substring);
3169 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003170 int from = offsets.at(i * 2);
3171 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003172 Handle<String> substring = isolate->factory()->
3173 NewProperSubString(subject, from, to);
3174 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003175 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003176 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003177 result->set_length(Smi::FromInt(matches));
3178 return *result;
3179}
3180
3181
lrn@chromium.org25156de2010-04-06 13:10:27 +00003182// Two smis before and after the match, for very long strings.
3183const int kMaxBuilderEntriesPerRegExpMatch = 5;
3184
3185
3186static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3187 Handle<JSArray> last_match_info,
3188 int match_start,
3189 int match_end) {
3190 // Fill last_match_info with a single capture.
3191 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3192 AssertNoAllocation no_gc;
3193 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3194 RegExpImpl::SetLastCaptureCount(elements, 2);
3195 RegExpImpl::SetLastInput(elements, *subject);
3196 RegExpImpl::SetLastSubject(elements, *subject);
3197 RegExpImpl::SetCapture(elements, 0, match_start);
3198 RegExpImpl::SetCapture(elements, 1, match_end);
3199}
3200
3201
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003202template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003203static bool SearchStringMultiple(Isolate* isolate,
3204 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003205 Vector<const PatternChar> pattern,
3206 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003207 FixedArrayBuilder* builder,
3208 int* match_pos) {
3209 int pos = *match_pos;
3210 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003211 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003212 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003213 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003214 while (pos <= max_search_start) {
3215 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3216 *match_pos = pos;
3217 return false;
3218 }
3219 // Position of end of previous match.
3220 int match_end = pos + pattern_length;
3221 int new_pos = search.Search(subject, match_end);
3222 if (new_pos >= 0) {
3223 // A match.
3224 if (new_pos > match_end) {
3225 ReplacementStringBuilder::AddSubjectSlice(builder,
3226 match_end,
3227 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003228 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003229 pos = new_pos;
3230 builder->Add(pattern_string);
3231 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003232 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003233 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003234 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003235
lrn@chromium.org25156de2010-04-06 13:10:27 +00003236 if (pos < max_search_start) {
3237 ReplacementStringBuilder::AddSubjectSlice(builder,
3238 pos + pattern_length,
3239 subject_length);
3240 }
3241 *match_pos = pos;
3242 return true;
3243}
3244
3245
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003246static bool SearchStringMultiple(Isolate* isolate,
3247 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003248 Handle<String> pattern,
3249 Handle<JSArray> last_match_info,
3250 FixedArrayBuilder* builder) {
3251 ASSERT(subject->IsFlat());
3252 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003253
3254 // Treating as if a previous match was before first character.
3255 int match_pos = -pattern->length();
3256
3257 for (;;) { // Break when search complete.
3258 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3259 AssertNoAllocation no_gc;
3260 if (subject->IsAsciiRepresentation()) {
3261 Vector<const char> subject_vector = subject->ToAsciiVector();
3262 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003263 if (SearchStringMultiple(isolate,
3264 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003265 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003266 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003267 builder,
3268 &match_pos)) break;
3269 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003270 if (SearchStringMultiple(isolate,
3271 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003272 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003273 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003274 builder,
3275 &match_pos)) break;
3276 }
3277 } else {
3278 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3279 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003280 if (SearchStringMultiple(isolate,
3281 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003282 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003283 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003284 builder,
3285 &match_pos)) break;
3286 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003287 if (SearchStringMultiple(isolate,
3288 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003289 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003290 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003291 builder,
3292 &match_pos)) break;
3293 }
3294 }
3295 }
3296
3297 if (match_pos >= 0) {
3298 SetLastMatchInfoNoCaptures(subject,
3299 last_match_info,
3300 match_pos,
3301 match_pos + pattern->length());
3302 return true;
3303 }
3304 return false; // No matches at all.
3305}
3306
3307
3308static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003309 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003310 Handle<String> subject,
3311 Handle<JSRegExp> regexp,
3312 Handle<JSArray> last_match_array,
3313 FixedArrayBuilder* builder) {
3314 ASSERT(subject->IsFlat());
3315 int match_start = -1;
3316 int match_end = 0;
3317 int pos = 0;
3318 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3319 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3320
3321 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003322 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003323 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003324 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003325
3326 for (;;) { // Break on failure, return on exception.
3327 RegExpImpl::IrregexpResult result =
3328 RegExpImpl::IrregexpExecOnce(regexp,
3329 subject,
3330 pos,
3331 register_vector);
3332 if (result == RegExpImpl::RE_SUCCESS) {
3333 match_start = register_vector[0];
3334 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3335 if (match_end < match_start) {
3336 ReplacementStringBuilder::AddSubjectSlice(builder,
3337 match_end,
3338 match_start);
3339 }
3340 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003341 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003342 if (!first) {
3343 builder->Add(*isolate->factory()->NewProperSubString(subject,
3344 match_start,
3345 match_end));
3346 } else {
3347 builder->Add(*isolate->factory()->NewSubString(subject,
3348 match_start,
3349 match_end));
3350 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003351 if (match_start != match_end) {
3352 pos = match_end;
3353 } else {
3354 pos = match_end + 1;
3355 if (pos > subject_length) break;
3356 }
3357 } else if (result == RegExpImpl::RE_FAILURE) {
3358 break;
3359 } else {
3360 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3361 return result;
3362 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003363 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003364 }
3365
3366 if (match_start >= 0) {
3367 if (match_end < subject_length) {
3368 ReplacementStringBuilder::AddSubjectSlice(builder,
3369 match_end,
3370 subject_length);
3371 }
3372 SetLastMatchInfoNoCaptures(subject,
3373 last_match_array,
3374 match_start,
3375 match_end);
3376 return RegExpImpl::RE_SUCCESS;
3377 } else {
3378 return RegExpImpl::RE_FAILURE; // No matches at all.
3379 }
3380}
3381
3382
3383static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003384 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003385 Handle<String> subject,
3386 Handle<JSRegExp> regexp,
3387 Handle<JSArray> last_match_array,
3388 FixedArrayBuilder* builder) {
3389
3390 ASSERT(subject->IsFlat());
3391 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3392 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3393
3394 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003395 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003396
3397 RegExpImpl::IrregexpResult result =
3398 RegExpImpl::IrregexpExecOnce(regexp,
3399 subject,
3400 0,
3401 register_vector);
3402
3403 int capture_count = regexp->CaptureCount();
3404 int subject_length = subject->length();
3405
3406 // Position to search from.
3407 int pos = 0;
3408 // End of previous match. Differs from pos if match was empty.
3409 int match_end = 0;
3410 if (result == RegExpImpl::RE_SUCCESS) {
3411 // Need to keep a copy of the previous match for creating last_match_info
3412 // at the end, so we have two vectors that we swap between.
3413 OffsetsVector registers2(required_registers);
3414 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003415 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003416 do {
3417 int match_start = register_vector[0];
3418 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3419 if (match_end < match_start) {
3420 ReplacementStringBuilder::AddSubjectSlice(builder,
3421 match_end,
3422 match_start);
3423 }
3424 match_end = register_vector[1];
3425
3426 {
3427 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003428 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003429 // Arguments array to replace function is match, captures, index and
3430 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003431 Handle<FixedArray> elements =
3432 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003433 Handle<String> match;
3434 if (!first) {
3435 match = isolate->factory()->NewProperSubString(subject,
3436 match_start,
3437 match_end);
3438 } else {
3439 match = isolate->factory()->NewSubString(subject,
3440 match_start,
3441 match_end);
3442 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003443 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003444 for (int i = 1; i <= capture_count; i++) {
3445 int start = register_vector[i * 2];
3446 if (start >= 0) {
3447 int end = register_vector[i * 2 + 1];
3448 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003449 Handle<String> substring;
3450 if (!first) {
3451 substring = isolate->factory()->NewProperSubString(subject,
3452 start,
3453 end);
3454 } else {
3455 substring = isolate->factory()->NewSubString(subject, start, end);
3456 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003457 elements->set(i, *substring);
3458 } else {
3459 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003460 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003461 }
3462 }
3463 elements->set(capture_count + 1, Smi::FromInt(match_start));
3464 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003465 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003466 }
3467 // Swap register vectors, so the last successful match is in
3468 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003469 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003470 prev_register_vector = register_vector;
3471 register_vector = tmp;
3472
3473 if (match_end > match_start) {
3474 pos = match_end;
3475 } else {
3476 pos = match_end + 1;
3477 if (pos > subject_length) {
3478 break;
3479 }
3480 }
3481
3482 result = RegExpImpl::IrregexpExecOnce(regexp,
3483 subject,
3484 pos,
3485 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003486 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003487 } while (result == RegExpImpl::RE_SUCCESS);
3488
3489 if (result != RegExpImpl::RE_EXCEPTION) {
3490 // Finished matching, with at least one match.
3491 if (match_end < subject_length) {
3492 ReplacementStringBuilder::AddSubjectSlice(builder,
3493 match_end,
3494 subject_length);
3495 }
3496
3497 int last_match_capture_count = (capture_count + 1) * 2;
3498 int last_match_array_size =
3499 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3500 last_match_array->EnsureSize(last_match_array_size);
3501 AssertNoAllocation no_gc;
3502 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3503 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3504 RegExpImpl::SetLastSubject(elements, *subject);
3505 RegExpImpl::SetLastInput(elements, *subject);
3506 for (int i = 0; i < last_match_capture_count; i++) {
3507 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3508 }
3509 return RegExpImpl::RE_SUCCESS;
3510 }
3511 }
3512 // No matches at all, return failure or exception result directly.
3513 return result;
3514}
3515
3516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003517RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003518 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003519 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003520
3521 CONVERT_ARG_CHECKED(String, subject, 1);
3522 if (!subject->IsFlat()) { FlattenString(subject); }
3523 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3524 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3525 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3526
3527 ASSERT(last_match_info->HasFastElements());
3528 ASSERT(regexp->GetFlags().is_global());
3529 Handle<FixedArray> result_elements;
3530 if (result_array->HasFastElements()) {
3531 result_elements =
3532 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003533 }
3534 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003535 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003536 }
3537 FixedArrayBuilder builder(result_elements);
3538
3539 if (regexp->TypeTag() == JSRegExp::ATOM) {
3540 Handle<String> pattern(
3541 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003542 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003543 if (SearchStringMultiple(isolate, subject, pattern,
3544 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003545 return *builder.ToJSArray(result_array);
3546 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003547 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003548 }
3549
3550 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3551
3552 RegExpImpl::IrregexpResult result;
3553 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003554 result = SearchRegExpNoCaptureMultiple(isolate,
3555 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003556 regexp,
3557 last_match_info,
3558 &builder);
3559 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003560 result = SearchRegExpMultiple(isolate,
3561 subject,
3562 regexp,
3563 last_match_info,
3564 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003565 }
3566 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003567 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003568 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3569 return Failure::Exception();
3570}
3571
3572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003573RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003574 NoHandleAllocation ha;
3575 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003576 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003577 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003578
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003579 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003580 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003581 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003582 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003583 // Character array used for conversion.
3584 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003585 return isolate->heap()->
3586 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003587 }
3588 }
3589
3590 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003591 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003593 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003594 }
3595 if (isinf(value)) {
3596 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003597 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003599 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003601 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 MaybeObject* result =
3603 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003604 DeleteArray(str);
3605 return result;
3606}
3607
3608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003609RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610 NoHandleAllocation ha;
3611 ASSERT(args.length() == 2);
3612
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003613 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003614 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003615 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 }
3617 if (isinf(value)) {
3618 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003623 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003624 int f = FastD2I(f_number);
3625 RUNTIME_ASSERT(f >= 0);
3626 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 MaybeObject* res =
3628 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003630 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631}
3632
3633
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003634RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003635 NoHandleAllocation ha;
3636 ASSERT(args.length() == 2);
3637
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003638 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003639 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003640 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 }
3642 if (isinf(value)) {
3643 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003644 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003645 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003646 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003647 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003648 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003649 int f = FastD2I(f_number);
3650 RUNTIME_ASSERT(f >= -1 && f <= 20);
3651 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003652 MaybeObject* res =
3653 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003654 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003655 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003656}
3657
3658
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003659RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003660 NoHandleAllocation ha;
3661 ASSERT(args.length() == 2);
3662
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003663 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003664 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003665 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003666 }
3667 if (isinf(value)) {
3668 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003669 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003670 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003671 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003672 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003673 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003674 int f = FastD2I(f_number);
3675 RUNTIME_ASSERT(f >= 1 && f <= 21);
3676 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003677 MaybeObject* res =
3678 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003679 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003680 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003681}
3682
3683
3684// Returns a single character string where first character equals
3685// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003686static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003687 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003688 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003689 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003690 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003691 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003692 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003693}
3694
3695
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003696MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3697 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003698 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003699 // Handle [] indexing on Strings
3700 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003701 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3702 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003703 }
3704
3705 // Handle [] indexing on String objects
3706 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003707 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3708 Handle<Object> result =
3709 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3710 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003711 }
3712
3713 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003714 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 return prototype->GetElement(index);
3716 }
3717
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003718 return GetElement(object, index);
3719}
3720
3721
lrn@chromium.org303ada72010-10-27 09:33:13 +00003722MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003723 return object->GetElement(index);
3724}
3725
3726
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003727MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3728 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003729 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003730 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003731
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003732 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003733 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003734 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003735 isolate->factory()->NewTypeError("non_object_property_load",
3736 HandleVector(args, 2));
3737 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003738 }
3739
3740 // Check if the given key is an array index.
3741 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003742 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003743 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003744 }
3745
3746 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003747 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003748 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003749 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003750 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003751 bool has_pending_exception = false;
3752 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003753 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003754 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003755 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003756 }
3757
ager@chromium.org32912102009-01-16 10:38:43 +00003758 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003759 // the element if so.
3760 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003761 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003762 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003763 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764 }
3765}
3766
3767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003768RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003769 NoHandleAllocation ha;
3770 ASSERT(args.length() == 2);
3771
3772 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003773 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003775 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003776}
3777
3778
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003779// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003780RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003781 NoHandleAllocation ha;
3782 ASSERT(args.length() == 2);
3783
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003784 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003785 // itself.
3786 //
3787 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003788 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003789 // global proxy object never has properties. This is the case
3790 // because the global proxy object forwards everything to its hidden
3791 // prototype including local lookups.
3792 //
3793 // Additionally, we need to make sure that we do not cache results
3794 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003795 if (args[0]->IsJSObject() &&
3796 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003797 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003798 args[1]->IsString()) {
3799 JSObject* receiver = JSObject::cast(args[0]);
3800 String* key = String::cast(args[1]);
3801 if (receiver->HasFastProperties()) {
3802 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003803 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003804 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3805 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003806 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003807 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003808 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003809 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003810 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003811 LookupResult result;
3812 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003813 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003814 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003815 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003816 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003817 }
3818 } else {
3819 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003820 StringDictionary* dictionary = receiver->property_dictionary();
3821 int entry = dictionary->FindEntry(key);
3822 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003823 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003824 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003825 if (!receiver->IsGlobalObject()) return value;
3826 value = JSGlobalPropertyCell::cast(value)->value();
3827 if (!value->IsTheHole()) return value;
3828 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003829 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003830 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003831 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3832 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003833 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003834 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003835 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003836 if (index >= 0 && index < str->length()) {
3837 Handle<Object> result = GetCharAt(str, index);
3838 return *result;
3839 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003840 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003841
3842 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003843 return Runtime::GetObjectProperty(isolate,
3844 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003845 args.at<Object>(1));
3846}
3847
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003848// Implements part of 8.12.9 DefineOwnProperty.
3849// There are 3 cases that lead here:
3850// Step 4b - define a new accessor property.
3851// Steps 9c & 12 - replace an existing data property with an accessor property.
3852// Step 12 - update an existing accessor property with an accessor or generic
3853// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003854RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003855 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003856 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003857 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3858 CONVERT_CHECKED(String, name, args[1]);
3859 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003860 Object* fun = args[3];
3861 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003862 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3863 int unchecked = flag_attr->value();
3864 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3865 RUNTIME_ASSERT(!obj->IsNull());
3866 LookupResult result;
3867 obj->LocalLookupRealNamedProperty(name, &result);
3868
3869 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3870 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3871 // delete it to avoid running into trouble in DefineAccessor, which
3872 // handles this incorrectly if the property is readonly (does nothing)
3873 if (result.IsProperty() &&
3874 (result.type() == FIELD || result.type() == NORMAL
3875 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003876 Object* ok;
3877 { MaybeObject* maybe_ok =
3878 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3879 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3880 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003881 }
3882 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3883}
3884
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003885// Implements part of 8.12.9 DefineOwnProperty.
3886// There are 3 cases that lead here:
3887// Step 4a - define a new data property.
3888// Steps 9b & 12 - replace an existing accessor property with a data property.
3889// Step 12 - update an existing data property with a data or generic
3890// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003891RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003892 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003893 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003894 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3895 CONVERT_ARG_CHECKED(String, name, 1);
3896 Handle<Object> obj_value = args.at<Object>(2);
3897
3898 CONVERT_CHECKED(Smi, flag, args[3]);
3899 int unchecked = flag->value();
3900 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3901
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003902 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3903
3904 // Check if this is an element.
3905 uint32_t index;
3906 bool is_element = name->AsArrayIndex(&index);
3907
3908 // Special case for elements if any of the flags are true.
3909 // If elements are in fast case we always implicitly assume that:
3910 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3911 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3912 is_element) {
3913 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003914 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003915 // We do not need to do access checks here since these has already
3916 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003917 Handle<Object> proto(js_object->GetPrototype());
3918 // If proxy is detached, ignore the assignment. Alternatively,
3919 // we could throw an exception.
3920 if (proto->IsNull()) return *obj_value;
3921 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003922 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003923 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003924 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003925 // Make sure that we never go back to fast case.
3926 dictionary->set_requires_slow_elements();
3927 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003928 Handle<NumberDictionary> extended_dictionary =
3929 NumberDictionarySet(dictionary, index, obj_value, details);
3930 if (*extended_dictionary != *dictionary) {
3931 js_object->set_elements(*extended_dictionary);
3932 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003933 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003934 }
3935
ager@chromium.org5c838252010-02-19 08:53:10 +00003936 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003937 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003938
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003939 // To be compatible with safari we do not change the value on API objects
3940 // in defineProperty. Firefox disagrees here, and actually changes the value.
3941 if (result.IsProperty() &&
3942 (result.type() == CALLBACKS) &&
3943 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003944 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003945 }
3946
ager@chromium.org5c838252010-02-19 08:53:10 +00003947 // Take special care when attributes are different and there is already
3948 // a property. For simplicity we normalize the property which enables us
3949 // to not worry about changing the instance_descriptor and creating a new
3950 // map. The current version of SetObjectProperty does not handle attributes
3951 // correctly in the case where a property is a field and is reset with
3952 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003953 if (result.IsProperty() &&
3954 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003955 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003956 if (js_object->IsJSGlobalProxy()) {
3957 // Since the result is a property, the prototype will exist so
3958 // we don't have to check for null.
3959 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003960 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003961 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003962 // Use IgnoreAttributes version since a readonly property may be
3963 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003964 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3965 *obj_value,
3966 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003967 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003968
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003969 return Runtime::ForceSetObjectProperty(isolate,
3970 js_object,
3971 name,
3972 obj_value,
3973 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003974}
3975
3976
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003977// Special case for elements if any of the flags are true.
3978// If elements are in fast case we always implicitly assume that:
3979// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3980static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
3981 Handle<JSObject> js_object,
3982 uint32_t index,
3983 Handle<Object> value,
3984 PropertyAttributes attr) {
3985 // Normalize the elements to enable attributes on the property.
3986 NormalizeElements(js_object);
3987 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
3988 // Make sure that we never go back to fast case.
3989 dictionary->set_requires_slow_elements();
3990 PropertyDetails details = PropertyDetails(attr, NORMAL);
3991 Handle<NumberDictionary> extended_dictionary =
3992 NumberDictionarySet(dictionary, index, value, details);
3993 if (*extended_dictionary != *dictionary) {
3994 js_object->set_elements(*extended_dictionary);
3995 }
3996 return *value;
3997}
3998
3999
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004000MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4001 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004002 Handle<Object> key,
4003 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004004 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004005 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004007
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004008 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004009 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004011 isolate->factory()->NewTypeError("non_object_property_store",
4012 HandleVector(args, 2));
4013 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 }
4015
4016 // If the object isn't a JavaScript object, we ignore the store.
4017 if (!object->IsJSObject()) return *value;
4018
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004019 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4020
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 // Check if the given key is an array index.
4022 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004023 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004024 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4025 // of a string using [] notation. We need to support this too in
4026 // JavaScript.
4027 // In the case of a String object we just need to redirect the assignment to
4028 // the underlying string if the index is in range. Since the underlying
4029 // string does nothing with the assignment then we can ignore such
4030 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004031 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004033 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004034
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004035 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4036 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4037 }
4038
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004039 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004040 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004041 return *value;
4042 }
4043
4044 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004045 Handle<Object> result;
4046 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004047 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4048 return NormalizeObjectSetElement(isolate,
4049 js_object,
4050 index,
4051 value,
4052 attr);
4053 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004054 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004055 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004056 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004057 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004058 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004060 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004061 return *value;
4062 }
4063
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004064 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065 bool has_pending_exception = false;
4066 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4067 if (has_pending_exception) return Failure::Exception();
4068 Handle<String> name = Handle<String>::cast(converted);
4069
4070 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004071 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004073 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004074 }
4075}
4076
4077
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004078MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4079 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004080 Handle<Object> key,
4081 Handle<Object> value,
4082 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004083 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004084
4085 // Check if the given key is an array index.
4086 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004087 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004088 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4089 // of a string using [] notation. We need to support this too in
4090 // JavaScript.
4091 // In the case of a String object we just need to redirect the assignment to
4092 // the underlying string if the index is in range. Since the underlying
4093 // string does nothing with the assignment then we can ignore such
4094 // assignments.
4095 if (js_object->IsStringObjectWithCharacterAt(index)) {
4096 return *value;
4097 }
4098
whesse@chromium.org7b260152011-06-20 15:33:18 +00004099 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004100 }
4101
4102 if (key->IsString()) {
4103 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004104 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004105 } else {
4106 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004107 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004108 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4109 *value,
4110 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004111 }
4112 }
4113
4114 // Call-back into JavaScript to convert the key to a string.
4115 bool has_pending_exception = false;
4116 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4117 if (has_pending_exception) return Failure::Exception();
4118 Handle<String> name = Handle<String>::cast(converted);
4119
4120 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004121 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004122 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004123 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004124 }
4125}
4126
4127
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004128MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4129 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004130 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004131 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004132
4133 // Check if the given key is an array index.
4134 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004135 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004136 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4137 // characters of a string using [] notation. In the case of a
4138 // String object we just need to redirect the deletion to the
4139 // underlying string if the index is in range. Since the
4140 // underlying string does nothing with the deletion, we can ignore
4141 // such deletions.
4142 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004143 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004144 }
4145
4146 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4147 }
4148
4149 Handle<String> key_string;
4150 if (key->IsString()) {
4151 key_string = Handle<String>::cast(key);
4152 } else {
4153 // Call-back into JavaScript to convert the key to a string.
4154 bool has_pending_exception = false;
4155 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4156 if (has_pending_exception) return Failure::Exception();
4157 key_string = Handle<String>::cast(converted);
4158 }
4159
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004160 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004161 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4162}
4163
4164
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004165RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004167 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004168
4169 Handle<Object> object = args.at<Object>(0);
4170 Handle<Object> key = args.at<Object>(1);
4171 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004172 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004173 RUNTIME_ASSERT(
4174 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004175 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004176 PropertyAttributes attributes =
4177 static_cast<PropertyAttributes>(unchecked_attributes);
4178
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004179 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004180 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004181 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004182 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4183 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004184 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004186
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004187 return Runtime::SetObjectProperty(isolate,
4188 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004189 key,
4190 value,
4191 attributes,
4192 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004193}
4194
4195
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004196// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004197// This is used to decide if we should transform null and undefined
4198// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004199RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004200 NoHandleAllocation ha;
4201 RUNTIME_ASSERT(args.length() == 1);
4202
4203 Handle<Object> object = args.at<Object>(0);
4204
4205 if (object->IsJSFunction()) {
4206 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004207 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004208 }
4209 return isolate->heap()->undefined_value();
4210}
4211
4212
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004213// Set a local property, even if it is READ_ONLY. If the property does not
4214// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004215RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004216 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004217 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 CONVERT_CHECKED(JSObject, object, args[0]);
4219 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004220 // Compute attributes.
4221 PropertyAttributes attributes = NONE;
4222 if (args.length() == 4) {
4223 CONVERT_CHECKED(Smi, value_obj, args[3]);
4224 int unchecked_value = value_obj->value();
4225 // Only attribute bits should be set.
4226 RUNTIME_ASSERT(
4227 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4228 attributes = static_cast<PropertyAttributes>(unchecked_value);
4229 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004231 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004232 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004233}
4234
4235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004236RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004237 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004238 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004239
4240 CONVERT_CHECKED(JSObject, object, args[0]);
4241 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004242 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004243 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004244 ? JSObject::STRICT_DELETION
4245 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004246}
4247
4248
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004249static Object* HasLocalPropertyImplementation(Isolate* isolate,
4250 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004251 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004252 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004253 // Handle hidden prototypes. If there's a hidden prototype above this thing
4254 // then we have to check it for properties, because they are supposed to
4255 // look like they are on this object.
4256 Handle<Object> proto(object->GetPrototype());
4257 if (proto->IsJSObject() &&
4258 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004259 return HasLocalPropertyImplementation(isolate,
4260 Handle<JSObject>::cast(proto),
4261 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004262 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004263 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004264}
4265
4266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004267RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004268 NoHandleAllocation ha;
4269 ASSERT(args.length() == 2);
4270 CONVERT_CHECKED(String, key, args[1]);
4271
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004272 uint32_t index;
4273 const bool key_is_array_index = key->AsArrayIndex(&index);
4274
ager@chromium.org9085a012009-05-11 19:22:57 +00004275 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004276 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004277 if (obj->IsJSObject()) {
4278 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004279 // Fast case: either the key is a real named property or it is not
4280 // an array index and there are no interceptors or hidden
4281 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004282 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004283 Map* map = object->map();
4284 if (!key_is_array_index &&
4285 !map->has_named_interceptor() &&
4286 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4287 return isolate->heap()->false_value();
4288 }
4289 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004290 HandleScope scope(isolate);
4291 return HasLocalPropertyImplementation(isolate,
4292 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004293 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004294 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004295 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004296 String* string = String::cast(obj);
4297 if (index < static_cast<uint32_t>(string->length())) {
4298 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004299 }
4300 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004301 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004302}
4303
4304
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004305RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004306 NoHandleAllocation na;
4307 ASSERT(args.length() == 2);
4308
4309 // Only JS objects can have properties.
4310 if (args[0]->IsJSObject()) {
4311 JSObject* object = JSObject::cast(args[0]);
4312 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004313 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004314 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004315 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004316}
4317
4318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004319RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004320 NoHandleAllocation na;
4321 ASSERT(args.length() == 2);
4322
4323 // Only JS objects can have elements.
4324 if (args[0]->IsJSObject()) {
4325 JSObject* object = JSObject::cast(args[0]);
4326 CONVERT_CHECKED(Smi, index_obj, args[1]);
4327 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004328 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004329 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004330 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004331}
4332
4333
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004334RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004335 NoHandleAllocation ha;
4336 ASSERT(args.length() == 2);
4337
4338 CONVERT_CHECKED(JSObject, object, args[0]);
4339 CONVERT_CHECKED(String, key, args[1]);
4340
4341 uint32_t index;
4342 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004343 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004344 }
4345
ager@chromium.org870a0b62008-11-04 11:43:05 +00004346 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004347 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004348}
4349
4350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004351RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004352 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004353 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004354 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004355 return *GetKeysFor(object);
4356}
4357
4358
4359// Returns either a FixedArray as Runtime_GetPropertyNames,
4360// or, if the given object has an enum cache that contains
4361// all enumerable properties of the object and its prototypes
4362// have none, the map of the object. This is used to speed up
4363// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004364RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004365 ASSERT(args.length() == 1);
4366
4367 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4368
4369 if (raw_object->IsSimpleEnum()) return raw_object->map();
4370
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004371 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004372 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004373 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4374 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004375
4376 // Test again, since cache may have been built by preceding call.
4377 if (object->IsSimpleEnum()) return object->map();
4378
4379 return *content;
4380}
4381
4382
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004383// Find the length of the prototype chain that is to to handled as one. If a
4384// prototype object is hidden it is to be viewed as part of the the object it
4385// is prototype for.
4386static int LocalPrototypeChainLength(JSObject* obj) {
4387 int count = 1;
4388 Object* proto = obj->GetPrototype();
4389 while (proto->IsJSObject() &&
4390 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4391 count++;
4392 proto = JSObject::cast(proto)->GetPrototype();
4393 }
4394 return count;
4395}
4396
4397
4398// Return the names of the local named properties.
4399// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004400RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004401 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004402 ASSERT(args.length() == 1);
4403 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004404 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004405 }
4406 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4407
4408 // Skip the global proxy as it has no properties and always delegates to the
4409 // real global object.
4410 if (obj->IsJSGlobalProxy()) {
4411 // Only collect names if access is permitted.
4412 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004413 !isolate->MayNamedAccess(*obj,
4414 isolate->heap()->undefined_value(),
4415 v8::ACCESS_KEYS)) {
4416 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4417 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004418 }
4419 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4420 }
4421
4422 // Find the number of objects making up this.
4423 int length = LocalPrototypeChainLength(*obj);
4424
4425 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004426 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004427 int total_property_count = 0;
4428 Handle<JSObject> jsproto = obj;
4429 for (int i = 0; i < length; i++) {
4430 // Only collect names if access is permitted.
4431 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004432 !isolate->MayNamedAccess(*jsproto,
4433 isolate->heap()->undefined_value(),
4434 v8::ACCESS_KEYS)) {
4435 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4436 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004437 }
4438 int n;
4439 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4440 local_property_count[i] = n;
4441 total_property_count += n;
4442 if (i < length - 1) {
4443 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4444 }
4445 }
4446
4447 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004448 Handle<FixedArray> names =
4449 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004450
4451 // Get the property names.
4452 jsproto = obj;
4453 int proto_with_hidden_properties = 0;
4454 for (int i = 0; i < length; i++) {
4455 jsproto->GetLocalPropertyNames(*names,
4456 i == 0 ? 0 : local_property_count[i - 1]);
4457 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4458 proto_with_hidden_properties++;
4459 }
4460 if (i < length - 1) {
4461 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4462 }
4463 }
4464
4465 // Filter out name of hidden propeties object.
4466 if (proto_with_hidden_properties > 0) {
4467 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004468 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004469 names->length() - proto_with_hidden_properties);
4470 int dest_pos = 0;
4471 for (int i = 0; i < total_property_count; i++) {
4472 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004473 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004474 continue;
4475 }
4476 names->set(dest_pos++, name);
4477 }
4478 }
4479
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004480 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004481}
4482
4483
4484// Return the names of the local indexed properties.
4485// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004486RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004487 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004488 ASSERT(args.length() == 1);
4489 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004490 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004491 }
4492 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4493
4494 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004495 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004496 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004497 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004498}
4499
4500
4501// Return information on whether an object has a named or indexed interceptor.
4502// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004503RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004504 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004505 ASSERT(args.length() == 1);
4506 if (!args[0]->IsJSObject()) {
4507 return Smi::FromInt(0);
4508 }
4509 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4510
4511 int result = 0;
4512 if (obj->HasNamedInterceptor()) result |= 2;
4513 if (obj->HasIndexedInterceptor()) result |= 1;
4514
4515 return Smi::FromInt(result);
4516}
4517
4518
4519// Return property names from named interceptor.
4520// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004521RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004522 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004523 ASSERT(args.length() == 1);
4524 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4525
4526 if (obj->HasNamedInterceptor()) {
4527 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4528 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4529 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004530 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004531}
4532
4533
4534// Return element names from indexed interceptor.
4535// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004536RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004537 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004538 ASSERT(args.length() == 1);
4539 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4540
4541 if (obj->HasIndexedInterceptor()) {
4542 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4543 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4544 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004545 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004546}
4547
4548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004549RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004550 ASSERT_EQ(args.length(), 1);
4551 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004552 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004553 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004554
4555 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004556 // Do access checks before going to the global object.
4557 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004558 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004559 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004560 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4561 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004562 }
4563
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004564 Handle<Object> proto(object->GetPrototype());
4565 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004566 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004567 object = Handle<JSObject>::cast(proto);
4568 }
4569
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004570 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4571 LOCAL_ONLY);
4572 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4573 // property array and since the result is mutable we have to create
4574 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004575 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004576 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004577 for (int i = 0; i < length; i++) {
4578 Object* entry = contents->get(i);
4579 if (entry->IsString()) {
4580 copy->set(i, entry);
4581 } else {
4582 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004583 HandleScope scope(isolate);
4584 Handle<Object> entry_handle(entry, isolate);
4585 Handle<Object> entry_str =
4586 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004587 copy->set(i, *entry_str);
4588 }
4589 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004590 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004591}
4592
4593
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004594RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004595 NoHandleAllocation ha;
4596 ASSERT(args.length() == 1);
4597
4598 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004599 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004600 it.AdvanceToArgumentsFrame();
4601 JavaScriptFrame* frame = it.frame();
4602
4603 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004604 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004605
4606 // Try to convert the key to an index. If successful and within
4607 // index return the the argument from the frame.
4608 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004609 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004610 return frame->GetParameter(index);
4611 }
4612
4613 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004614 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004615 bool exception = false;
4616 Handle<Object> converted =
4617 Execution::ToString(args.at<Object>(0), &exception);
4618 if (exception) return Failure::Exception();
4619 Handle<String> key = Handle<String>::cast(converted);
4620
4621 // Try to convert the string key into an array index.
4622 if (key->AsArrayIndex(&index)) {
4623 if (index < n) {
4624 return frame->GetParameter(index);
4625 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004626 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004627 }
4628 }
4629
4630 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004631 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4632 if (key->Equals(isolate->heap()->callee_symbol())) {
4633 Object* function = frame->function();
4634 if (function->IsJSFunction() &&
4635 JSFunction::cast(function)->shared()->strict_mode()) {
4636 return isolate->Throw(*isolate->factory()->NewTypeError(
4637 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4638 }
4639 return function;
4640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004641
4642 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004643 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004644}
4645
4646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004647RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004648 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004649
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004650 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004651 Handle<Object> object = args.at<Object>(0);
4652 if (object->IsJSObject()) {
4653 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004654 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004655 MaybeObject* ok = js_object->TransformToFastProperties(0);
4656 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004657 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004658 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004659 return *object;
4660}
4661
4662
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004663RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004664 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004665
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004666 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004667 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004668 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004669 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004670 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004671 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004672 return *object;
4673}
4674
4675
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004676RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004677 NoHandleAllocation ha;
4678 ASSERT(args.length() == 1);
4679
4680 return args[0]->ToBoolean();
4681}
4682
4683
4684// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4685// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004686RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004687 NoHandleAllocation ha;
4688
4689 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004690 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004691 HeapObject* heap_obj = HeapObject::cast(obj);
4692
4693 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004694 if (heap_obj->map()->is_undetectable()) {
4695 return isolate->heap()->undefined_symbol();
4696 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004697
4698 InstanceType instance_type = heap_obj->map()->instance_type();
4699 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004700 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004701 }
4702
4703 switch (instance_type) {
4704 case ODDBALL_TYPE:
4705 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004706 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004707 }
4708 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004709 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710 }
4711 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004712 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004713 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004714 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004715 default:
4716 // For any kind of object not handled above, the spec rule for
4717 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004718 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004719 }
4720}
4721
4722
lrn@chromium.org25156de2010-04-06 13:10:27 +00004723static bool AreDigits(const char*s, int from, int to) {
4724 for (int i = from; i < to; i++) {
4725 if (s[i] < '0' || s[i] > '9') return false;
4726 }
4727
4728 return true;
4729}
4730
4731
4732static int ParseDecimalInteger(const char*s, int from, int to) {
4733 ASSERT(to - from < 10); // Overflow is not possible.
4734 ASSERT(from < to);
4735 int d = s[from] - '0';
4736
4737 for (int i = from + 1; i < to; i++) {
4738 d = 10 * d + (s[i] - '0');
4739 }
4740
4741 return d;
4742}
4743
4744
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004745RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004746 NoHandleAllocation ha;
4747 ASSERT(args.length() == 1);
4748 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004749 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004750
4751 // Fast case: short integer or some sorts of junk values.
4752 int len = subject->length();
4753 if (subject->IsSeqAsciiString()) {
4754 if (len == 0) return Smi::FromInt(0);
4755
4756 char const* data = SeqAsciiString::cast(subject)->GetChars();
4757 bool minus = (data[0] == '-');
4758 int start_pos = (minus ? 1 : 0);
4759
4760 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004761 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004762 } else if (data[start_pos] > '9') {
4763 // Fast check for a junk value. A valid string may start from a
4764 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4765 // the 'I' character ('Infinity'). All of that have codes not greater than
4766 // '9' except 'I'.
4767 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004768 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004769 }
4770 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4771 // The maximal/minimal smi has 10 digits. If the string has less digits we
4772 // know it will fit into the smi-data type.
4773 int d = ParseDecimalInteger(data, start_pos, len);
4774 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004775 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004776 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004777 } else if (!subject->HasHashCode() &&
4778 len <= String::kMaxArrayIndexSize &&
4779 (len == 1 || data[0] != '0')) {
4780 // String hash is not calculated yet but all the data are present.
4781 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004782 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004783#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004784 subject->Hash(); // Force hash calculation.
4785 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4786 static_cast<int>(hash));
4787#endif
4788 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004789 }
4790 return Smi::FromInt(d);
4791 }
4792 }
4793
4794 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004795 return isolate->heap()->NumberFromDouble(
4796 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004797}
4798
4799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004800RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004801 NoHandleAllocation ha;
4802 ASSERT(args.length() == 1);
4803
4804 CONVERT_CHECKED(JSArray, codes, args[0]);
4805 int length = Smi::cast(codes->length())->value();
4806
4807 // Check if the string can be ASCII.
4808 int i;
4809 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004810 Object* element;
4811 { MaybeObject* maybe_element = codes->GetElement(i);
4812 // We probably can't get an exception here, but just in order to enforce
4813 // the checking of inputs in the runtime calls we check here.
4814 if (!maybe_element->ToObject(&element)) return maybe_element;
4815 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004816 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4817 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4818 break;
4819 }
4820
lrn@chromium.org303ada72010-10-27 09:33:13 +00004821 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004823 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004824 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004825 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004826 }
4827
lrn@chromium.org303ada72010-10-27 09:33:13 +00004828 Object* object = NULL;
4829 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830 String* result = String::cast(object);
4831 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004832 Object* element;
4833 { MaybeObject* maybe_element = codes->GetElement(i);
4834 if (!maybe_element->ToObject(&element)) return maybe_element;
4835 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004836 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004837 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004838 }
4839 return result;
4840}
4841
4842
4843// kNotEscaped is generated by the following:
4844//
4845// #!/bin/perl
4846// for (my $i = 0; $i < 256; $i++) {
4847// print "\n" if $i % 16 == 0;
4848// my $c = chr($i);
4849// my $escaped = 1;
4850// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4851// print $escaped ? "0, " : "1, ";
4852// }
4853
4854
4855static bool IsNotEscaped(uint16_t character) {
4856 // Only for 8 bit characters, the rest are always escaped (in a different way)
4857 ASSERT(character < 256);
4858 static const char kNotEscaped[256] = {
4859 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4860 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4861 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4862 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4863 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4864 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4865 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4866 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4867 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4868 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4869 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4870 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4871 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4872 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4873 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4874 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4875 };
4876 return kNotEscaped[character] != 0;
4877}
4878
4879
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004880RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004881 const char hex_chars[] = "0123456789ABCDEF";
4882 NoHandleAllocation ha;
4883 ASSERT(args.length() == 1);
4884 CONVERT_CHECKED(String, source, args[0]);
4885
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004886 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004887
4888 int escaped_length = 0;
4889 int length = source->length();
4890 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004891 Access<StringInputBuffer> buffer(
4892 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893 buffer->Reset(source);
4894 while (buffer->has_more()) {
4895 uint16_t character = buffer->GetNext();
4896 if (character >= 256) {
4897 escaped_length += 6;
4898 } else if (IsNotEscaped(character)) {
4899 escaped_length++;
4900 } else {
4901 escaped_length += 3;
4902 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004903 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004904 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004905 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004906 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004907 return Failure::OutOfMemoryException();
4908 }
4909 }
4910 }
4911 // No length change implies no change. Return original string if no change.
4912 if (escaped_length == length) {
4913 return source;
4914 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004915 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004916 { MaybeObject* maybe_o =
4917 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004918 if (!maybe_o->ToObject(&o)) return maybe_o;
4919 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004920 String* destination = String::cast(o);
4921 int dest_position = 0;
4922
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004923 Access<StringInputBuffer> buffer(
4924 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004925 buffer->Rewind();
4926 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004927 uint16_t chr = buffer->GetNext();
4928 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004929 destination->Set(dest_position, '%');
4930 destination->Set(dest_position+1, 'u');
4931 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4932 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4933 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4934 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004935 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004936 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004937 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004938 dest_position++;
4939 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004940 destination->Set(dest_position, '%');
4941 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4942 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004943 dest_position += 3;
4944 }
4945 }
4946 return destination;
4947}
4948
4949
4950static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4951 static const signed char kHexValue['g'] = {
4952 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4953 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4954 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4955 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4956 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4957 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4958 -1, 10, 11, 12, 13, 14, 15 };
4959
4960 if (character1 > 'f') return -1;
4961 int hi = kHexValue[character1];
4962 if (hi == -1) return -1;
4963 if (character2 > 'f') return -1;
4964 int lo = kHexValue[character2];
4965 if (lo == -1) return -1;
4966 return (hi << 4) + lo;
4967}
4968
4969
ager@chromium.org870a0b62008-11-04 11:43:05 +00004970static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004971 int i,
4972 int length,
4973 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004974 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004975 int32_t hi = 0;
4976 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004977 if (character == '%' &&
4978 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004979 source->Get(i + 1) == 'u' &&
4980 (hi = TwoDigitHex(source->Get(i + 2),
4981 source->Get(i + 3))) != -1 &&
4982 (lo = TwoDigitHex(source->Get(i + 4),
4983 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004984 *step = 6;
4985 return (hi << 8) + lo;
4986 } else if (character == '%' &&
4987 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004988 (lo = TwoDigitHex(source->Get(i + 1),
4989 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004990 *step = 3;
4991 return lo;
4992 } else {
4993 *step = 1;
4994 return character;
4995 }
4996}
4997
4998
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004999RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005000 NoHandleAllocation ha;
5001 ASSERT(args.length() == 1);
5002 CONVERT_CHECKED(String, source, args[0]);
5003
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005004 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005005
5006 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005007 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005008
5009 int unescaped_length = 0;
5010 for (int i = 0; i < length; unescaped_length++) {
5011 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005012 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005013 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005014 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005015 i += step;
5016 }
5017
5018 // No length change implies no change. Return original string if no change.
5019 if (unescaped_length == length)
5020 return source;
5021
lrn@chromium.org303ada72010-10-27 09:33:13 +00005022 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005023 { MaybeObject* maybe_o =
5024 ascii ?
5025 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5026 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005027 if (!maybe_o->ToObject(&o)) return maybe_o;
5028 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005029 String* destination = String::cast(o);
5030
5031 int dest_position = 0;
5032 for (int i = 0; i < length; dest_position++) {
5033 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005034 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005035 i += step;
5036 }
5037 return destination;
5038}
5039
5040
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005041static const unsigned int kQuoteTableLength = 128u;
5042
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005043static const int kJsonQuotesCharactersPerEntry = 8;
5044static const char* const JsonQuotes =
5045 "\\u0000 \\u0001 \\u0002 \\u0003 "
5046 "\\u0004 \\u0005 \\u0006 \\u0007 "
5047 "\\b \\t \\n \\u000b "
5048 "\\f \\r \\u000e \\u000f "
5049 "\\u0010 \\u0011 \\u0012 \\u0013 "
5050 "\\u0014 \\u0015 \\u0016 \\u0017 "
5051 "\\u0018 \\u0019 \\u001a \\u001b "
5052 "\\u001c \\u001d \\u001e \\u001f "
5053 " ! \\\" # "
5054 "$ % & ' "
5055 "( ) * + "
5056 ", - . / "
5057 "0 1 2 3 "
5058 "4 5 6 7 "
5059 "8 9 : ; "
5060 "< = > ? "
5061 "@ A B C "
5062 "D E F G "
5063 "H I J K "
5064 "L M N O "
5065 "P Q R S "
5066 "T U V W "
5067 "X Y Z [ "
5068 "\\\\ ] ^ _ "
5069 "` a b c "
5070 "d e f g "
5071 "h i j k "
5072 "l m n o "
5073 "p q r s "
5074 "t u v w "
5075 "x y z { "
5076 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005077
5078
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005079// For a string that is less than 32k characters it should always be
5080// possible to allocate it in new space.
5081static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5082
5083
5084// Doing JSON quoting cannot make the string more than this many times larger.
5085static const int kJsonQuoteWorstCaseBlowup = 6;
5086
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005087static const int kSpaceForQuotesAndComma = 3;
5088static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005089
5090// Covers the entire ASCII range (all other characters are unchanged by JSON
5091// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005092static const byte JsonQuoteLengths[kQuoteTableLength] = {
5093 6, 6, 6, 6, 6, 6, 6, 6,
5094 2, 2, 2, 6, 2, 2, 6, 6,
5095 6, 6, 6, 6, 6, 6, 6, 6,
5096 6, 6, 6, 6, 6, 6, 6, 6,
5097 1, 1, 2, 1, 1, 1, 1, 1,
5098 1, 1, 1, 1, 1, 1, 1, 1,
5099 1, 1, 1, 1, 1, 1, 1, 1,
5100 1, 1, 1, 1, 1, 1, 1, 1,
5101 1, 1, 1, 1, 1, 1, 1, 1,
5102 1, 1, 1, 1, 1, 1, 1, 1,
5103 1, 1, 1, 1, 1, 1, 1, 1,
5104 1, 1, 1, 1, 2, 1, 1, 1,
5105 1, 1, 1, 1, 1, 1, 1, 1,
5106 1, 1, 1, 1, 1, 1, 1, 1,
5107 1, 1, 1, 1, 1, 1, 1, 1,
5108 1, 1, 1, 1, 1, 1, 1, 1,
5109};
5110
5111
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005112template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005113MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005114
5115
5116template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005117MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5118 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005119}
5120
5121
5122template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005123MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5124 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005125}
5126
5127
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005128template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005129static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5130 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005131 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005132 const Char* read_cursor = characters.start();
5133 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005134 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005135 int quoted_length = kSpaceForQuotes;
5136 while (read_cursor < end) {
5137 Char c = *(read_cursor++);
5138 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5139 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005140 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005141 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005142 }
5143 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005144 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5145 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005146 Object* new_object;
5147 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005148 return new_alloc;
5149 }
5150 StringType* new_string = StringType::cast(new_object);
5151
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005152 Char* write_cursor = reinterpret_cast<Char*>(
5153 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005154 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005155 *(write_cursor++) = '"';
5156
5157 read_cursor = characters.start();
5158 while (read_cursor < end) {
5159 Char c = *(read_cursor++);
5160 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5161 *(write_cursor++) = c;
5162 } else {
5163 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5164 const char* replacement = JsonQuotes +
5165 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5166 for (int i = 0; i < len; i++) {
5167 *write_cursor++ = *replacement++;
5168 }
5169 }
5170 }
5171 *(write_cursor++) = '"';
5172 return new_string;
5173}
5174
5175
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005176template <typename SinkChar, typename SourceChar>
5177static inline SinkChar* WriteQuoteJsonString(
5178 Isolate* isolate,
5179 SinkChar* write_cursor,
5180 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005181 // SinkChar is only char if SourceChar is guaranteed to be char.
5182 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005183 const SourceChar* read_cursor = characters.start();
5184 const SourceChar* end = read_cursor + characters.length();
5185 *(write_cursor++) = '"';
5186 while (read_cursor < end) {
5187 SourceChar c = *(read_cursor++);
5188 if (sizeof(SourceChar) > 1u &&
5189 static_cast<unsigned>(c) >= kQuoteTableLength) {
5190 *(write_cursor++) = static_cast<SinkChar>(c);
5191 } else {
5192 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5193 const char* replacement = JsonQuotes +
5194 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5195 write_cursor[0] = replacement[0];
5196 if (len > 1) {
5197 write_cursor[1] = replacement[1];
5198 if (len > 2) {
5199 ASSERT(len == 6);
5200 write_cursor[2] = replacement[2];
5201 write_cursor[3] = replacement[3];
5202 write_cursor[4] = replacement[4];
5203 write_cursor[5] = replacement[5];
5204 }
5205 }
5206 write_cursor += len;
5207 }
5208 }
5209 *(write_cursor++) = '"';
5210 return write_cursor;
5211}
5212
5213
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005214template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215static MaybeObject* QuoteJsonString(Isolate* isolate,
5216 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005217 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005218 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005219 int worst_case_length =
5220 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005221 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005222 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005223 }
5224
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005225 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5226 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005227 Object* new_object;
5228 if (!new_alloc->ToObject(&new_object)) {
5229 return new_alloc;
5230 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005231 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005232 // Even if our string is small enough to fit in new space we still have to
5233 // handle it being allocated in old space as may happen in the third
5234 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5235 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005236 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005237 }
5238 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005239 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005240
5241 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5242 Char* write_cursor = reinterpret_cast<Char*>(
5243 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005244 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005245 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5246 write_cursor,
5247 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005248 int final_length = static_cast<int>(
5249 write_cursor - reinterpret_cast<Char*>(
5250 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005251 isolate->heap()->new_space()->
5252 template ShrinkStringAtAllocationBoundary<StringType>(
5253 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005254 return new_string;
5255}
5256
5257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005258RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005259 NoHandleAllocation ha;
5260 CONVERT_CHECKED(String, str, args[0]);
5261 if (!str->IsFlat()) {
5262 MaybeObject* try_flatten = str->TryFlatten();
5263 Object* flat;
5264 if (!try_flatten->ToObject(&flat)) {
5265 return try_flatten;
5266 }
5267 str = String::cast(flat);
5268 ASSERT(str->IsFlat());
5269 }
5270 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005271 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5272 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005273 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005274 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5275 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005276 }
5277}
5278
5279
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005280RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005281 NoHandleAllocation ha;
5282 CONVERT_CHECKED(String, str, args[0]);
5283 if (!str->IsFlat()) {
5284 MaybeObject* try_flatten = str->TryFlatten();
5285 Object* flat;
5286 if (!try_flatten->ToObject(&flat)) {
5287 return try_flatten;
5288 }
5289 str = String::cast(flat);
5290 ASSERT(str->IsFlat());
5291 }
5292 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005293 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5294 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005295 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005296 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5297 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005298 }
5299}
5300
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005301
5302template <typename Char, typename StringType>
5303static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5304 FixedArray* array,
5305 int worst_case_length) {
5306 int length = array->length();
5307
5308 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5309 worst_case_length);
5310 Object* new_object;
5311 if (!new_alloc->ToObject(&new_object)) {
5312 return new_alloc;
5313 }
5314 if (!isolate->heap()->new_space()->Contains(new_object)) {
5315 // Even if our string is small enough to fit in new space we still have to
5316 // handle it being allocated in old space as may happen in the third
5317 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5318 // CEntryStub::GenerateCore.
5319 return isolate->heap()->undefined_value();
5320 }
5321 AssertNoAllocation no_gc;
5322 StringType* new_string = StringType::cast(new_object);
5323 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5324
5325 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5326 Char* write_cursor = reinterpret_cast<Char*>(
5327 new_string->address() + SeqAsciiString::kHeaderSize);
5328 *(write_cursor++) = '[';
5329 for (int i = 0; i < length; i++) {
5330 if (i != 0) *(write_cursor++) = ',';
5331 String* str = String::cast(array->get(i));
5332 if (str->IsTwoByteRepresentation()) {
5333 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5334 write_cursor,
5335 str->ToUC16Vector());
5336 } else {
5337 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5338 write_cursor,
5339 str->ToAsciiVector());
5340 }
5341 }
5342 *(write_cursor++) = ']';
5343
5344 int final_length = static_cast<int>(
5345 write_cursor - reinterpret_cast<Char*>(
5346 new_string->address() + SeqAsciiString::kHeaderSize));
5347 isolate->heap()->new_space()->
5348 template ShrinkStringAtAllocationBoundary<StringType>(
5349 new_string, final_length);
5350 return new_string;
5351}
5352
5353
5354RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5355 NoHandleAllocation ha;
5356 ASSERT(args.length() == 1);
5357 CONVERT_CHECKED(JSArray, array, args[0]);
5358
5359 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5360 FixedArray* elements = FixedArray::cast(array->elements());
5361 int n = elements->length();
5362 bool ascii = true;
5363 int total_length = 0;
5364
5365 for (int i = 0; i < n; i++) {
5366 Object* elt = elements->get(i);
5367 if (!elt->IsString()) return isolate->heap()->undefined_value();
5368 String* element = String::cast(elt);
5369 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5370 total_length += element->length();
5371 if (ascii && element->IsTwoByteRepresentation()) {
5372 ascii = false;
5373 }
5374 }
5375
5376 int worst_case_length =
5377 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5378 + total_length * kJsonQuoteWorstCaseBlowup;
5379
5380 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5381 return isolate->heap()->undefined_value();
5382 }
5383
5384 if (ascii) {
5385 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5386 elements,
5387 worst_case_length);
5388 } else {
5389 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5390 elements,
5391 worst_case_length);
5392 }
5393}
5394
5395
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005396RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005397 NoHandleAllocation ha;
5398
5399 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005400 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005401
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005402 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005403
lrn@chromium.org25156de2010-04-06 13:10:27 +00005404 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005405 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005406 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005407}
5408
5409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005410RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005411 NoHandleAllocation ha;
5412 CONVERT_CHECKED(String, str, args[0]);
5413
5414 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005415 double value = StringToDouble(isolate->unicode_cache(),
5416 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005417
5418 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005419 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005420}
5421
5422
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005423template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005424MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005425 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005426 String* s,
5427 int length,
5428 int input_string_length,
5429 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005430 // We try this twice, once with the assumption that the result is no longer
5431 // than the input and, if that assumption breaks, again with the exact
5432 // length. This may not be pretty, but it is nicer than what was here before
5433 // and I hereby claim my vaffel-is.
5434 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005435 // Allocate the resulting string.
5436 //
5437 // NOTE: This assumes that the upper/lower case of an ascii
5438 // character is also ascii. This is currently the case, but it
5439 // might break in the future if we implement more context and locale
5440 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005441 Object* o;
5442 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005443 ? isolate->heap()->AllocateRawAsciiString(length)
5444 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005445 if (!maybe_o->ToObject(&o)) return maybe_o;
5446 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005447 String* result = String::cast(o);
5448 bool has_changed_character = false;
5449
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005450 // Convert all characters to upper case, assuming that they will fit
5451 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005452 Access<StringInputBuffer> buffer(
5453 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005454 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005455 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005456 // We can assume that the string is not empty
5457 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005458 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005459 bool has_next = buffer->has_more();
5460 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005461 int char_length = mapping->get(current, next, chars);
5462 if (char_length == 0) {
5463 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005464 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465 i++;
5466 } else if (char_length == 1) {
5467 // Common case: converting the letter resulted in one character.
5468 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005469 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005470 has_changed_character = true;
5471 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005472 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005473 // We've assumed that the result would be as long as the
5474 // input but here is a character that converts to several
5475 // characters. No matter, we calculate the exact length
5476 // of the result and try the whole thing again.
5477 //
5478 // Note that this leaves room for optimization. We could just
5479 // memcpy what we already have to the result string. Also,
5480 // the result string is the last object allocated we could
5481 // "realloc" it and probably, in the vast majority of cases,
5482 // extend the existing string to be able to hold the full
5483 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005484 int next_length = 0;
5485 if (has_next) {
5486 next_length = mapping->get(next, 0, chars);
5487 if (next_length == 0) next_length = 1;
5488 }
5489 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005490 while (buffer->has_more()) {
5491 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005492 // NOTE: we use 0 as the next character here because, while
5493 // the next character may affect what a character converts to,
5494 // it does not in any case affect the length of what it convert
5495 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005496 int char_length = mapping->get(current, 0, chars);
5497 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005498 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005499 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005500 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005501 return Failure::OutOfMemoryException();
5502 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005503 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005504 // Try again with the real length.
5505 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005506 } else {
5507 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005508 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005509 i++;
5510 }
5511 has_changed_character = true;
5512 }
5513 current = next;
5514 }
5515 if (has_changed_character) {
5516 return result;
5517 } else {
5518 // If we didn't actually change anything in doing the conversion
5519 // we simple return the result and let the converted string
5520 // become garbage; there is no reason to keep two identical strings
5521 // alive.
5522 return s;
5523 }
5524}
5525
5526
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005527namespace {
5528
lrn@chromium.org303ada72010-10-27 09:33:13 +00005529static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5530
5531
5532// Given a word and two range boundaries returns a word with high bit
5533// set in every byte iff the corresponding input byte was strictly in
5534// the range (m, n). All the other bits in the result are cleared.
5535// This function is only useful when it can be inlined and the
5536// boundaries are statically known.
5537// Requires: all bytes in the input word and the boundaries must be
5538// ascii (less than 0x7F).
5539static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5540 // Every byte in an ascii string is less than or equal to 0x7F.
5541 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5542 // Use strict inequalities since in edge cases the function could be
5543 // further simplified.
5544 ASSERT(0 < m && m < n && n < 0x7F);
5545 // Has high bit set in every w byte less than n.
5546 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5547 // Has high bit set in every w byte greater than m.
5548 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5549 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5550}
5551
5552
5553enum AsciiCaseConversion {
5554 ASCII_TO_LOWER,
5555 ASCII_TO_UPPER
5556};
5557
5558
5559template <AsciiCaseConversion dir>
5560struct FastAsciiConverter {
5561 static bool Convert(char* dst, char* src, int length) {
5562#ifdef DEBUG
5563 char* saved_dst = dst;
5564 char* saved_src = src;
5565#endif
5566 // We rely on the distance between upper and lower case letters
5567 // being a known power of 2.
5568 ASSERT('a' - 'A' == (1 << 5));
5569 // Boundaries for the range of input characters than require conversion.
5570 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5571 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5572 bool changed = false;
5573 char* const limit = src + length;
5574#ifdef V8_HOST_CAN_READ_UNALIGNED
5575 // Process the prefix of the input that requires no conversion one
5576 // (machine) word at a time.
5577 while (src <= limit - sizeof(uintptr_t)) {
5578 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5579 if (AsciiRangeMask(w, lo, hi) != 0) {
5580 changed = true;
5581 break;
5582 }
5583 *reinterpret_cast<uintptr_t*>(dst) = w;
5584 src += sizeof(uintptr_t);
5585 dst += sizeof(uintptr_t);
5586 }
5587 // Process the remainder of the input performing conversion when
5588 // required one word at a time.
5589 while (src <= limit - sizeof(uintptr_t)) {
5590 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5591 uintptr_t m = AsciiRangeMask(w, lo, hi);
5592 // The mask has high (7th) bit set in every byte that needs
5593 // conversion and we know that the distance between cases is
5594 // 1 << 5.
5595 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5596 src += sizeof(uintptr_t);
5597 dst += sizeof(uintptr_t);
5598 }
5599#endif
5600 // Process the last few bytes of the input (or the whole input if
5601 // unaligned access is not supported).
5602 while (src < limit) {
5603 char c = *src;
5604 if (lo < c && c < hi) {
5605 c ^= (1 << 5);
5606 changed = true;
5607 }
5608 *dst = c;
5609 ++src;
5610 ++dst;
5611 }
5612#ifdef DEBUG
5613 CheckConvert(saved_dst, saved_src, length, changed);
5614#endif
5615 return changed;
5616 }
5617
5618#ifdef DEBUG
5619 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5620 bool expected_changed = false;
5621 for (int i = 0; i < length; i++) {
5622 if (dst[i] == src[i]) continue;
5623 expected_changed = true;
5624 if (dir == ASCII_TO_LOWER) {
5625 ASSERT('A' <= src[i] && src[i] <= 'Z');
5626 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5627 } else {
5628 ASSERT(dir == ASCII_TO_UPPER);
5629 ASSERT('a' <= src[i] && src[i] <= 'z');
5630 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5631 }
5632 }
5633 ASSERT(expected_changed == changed);
5634 }
5635#endif
5636};
5637
5638
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005639struct ToLowerTraits {
5640 typedef unibrow::ToLowercase UnibrowConverter;
5641
lrn@chromium.org303ada72010-10-27 09:33:13 +00005642 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005643};
5644
5645
5646struct ToUpperTraits {
5647 typedef unibrow::ToUppercase UnibrowConverter;
5648
lrn@chromium.org303ada72010-10-27 09:33:13 +00005649 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005650};
5651
5652} // namespace
5653
5654
5655template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005656MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005657 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005658 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005659 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005660 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005661 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005662 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005663
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005664 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005665 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005666 if (length == 0) return s;
5667
5668 // Simpler handling of ascii strings.
5669 //
5670 // NOTE: This assumes that the upper/lower case of an ascii
5671 // character is also ascii. This is currently the case, but it
5672 // might break in the future if we implement more context and locale
5673 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005674 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005675 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005676 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005677 if (!maybe_o->ToObject(&o)) return maybe_o;
5678 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005679 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005680 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005681 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005682 return has_changed_character ? result : s;
5683 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005684
lrn@chromium.org303ada72010-10-27 09:33:13 +00005685 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005686 { MaybeObject* maybe_answer =
5687 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005688 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5689 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005690 if (answer->IsSmi()) {
5691 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005692 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005693 ConvertCaseHelper(isolate,
5694 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005695 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5696 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005697 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005698 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005699}
5700
5701
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005702RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005703 return ConvertCase<ToLowerTraits>(
5704 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005705}
5706
5707
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005708RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005709 return ConvertCase<ToUpperTraits>(
5710 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005711}
5712
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005713
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005714static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5715 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5716}
5717
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005719RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005720 NoHandleAllocation ha;
5721 ASSERT(args.length() == 3);
5722
5723 CONVERT_CHECKED(String, s, args[0]);
5724 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5725 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5726
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005727 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005728 int length = s->length();
5729
5730 int left = 0;
5731 if (trimLeft) {
5732 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5733 left++;
5734 }
5735 }
5736
5737 int right = length;
5738 if (trimRight) {
5739 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5740 right--;
5741 }
5742 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005743 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005744}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005745
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005746
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005747template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005748void FindStringIndices(Isolate* isolate,
5749 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005750 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005751 ZoneList<int>* indices,
5752 unsigned int limit) {
5753 ASSERT(limit > 0);
5754 // Collect indices of pattern in subject, and the end-of-string index.
5755 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005756 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005757 int pattern_length = pattern.length();
5758 int index = 0;
5759 while (limit > 0) {
5760 index = search.Search(subject, index);
5761 if (index < 0) return;
5762 indices->Add(index);
5763 index += pattern_length;
5764 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005765 }
5766}
5767
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005769RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005770 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005771 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005772 CONVERT_ARG_CHECKED(String, subject, 0);
5773 CONVERT_ARG_CHECKED(String, pattern, 1);
5774 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5775
5776 int subject_length = subject->length();
5777 int pattern_length = pattern->length();
5778 RUNTIME_ASSERT(pattern_length > 0);
5779
5780 // The limit can be very large (0xffffffffu), but since the pattern
5781 // isn't empty, we can never create more parts than ~half the length
5782 // of the subject.
5783
5784 if (!subject->IsFlat()) FlattenString(subject);
5785
5786 static const int kMaxInitialListCapacity = 16;
5787
danno@chromium.org40cb8782011-05-25 07:58:50 +00005788 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005789
5790 // Find (up to limit) indices of separator and end-of-string in subject
5791 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5792 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005793 if (!pattern->IsFlat()) FlattenString(pattern);
5794
5795 // No allocation block.
5796 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005797 AssertNoAllocation nogc;
5798 if (subject->IsAsciiRepresentation()) {
5799 Vector<const char> subject_vector = subject->ToAsciiVector();
5800 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005801 FindStringIndices(isolate,
5802 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005803 pattern->ToAsciiVector(),
5804 &indices,
5805 limit);
5806 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005807 FindStringIndices(isolate,
5808 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005809 pattern->ToUC16Vector(),
5810 &indices,
5811 limit);
5812 }
5813 } else {
5814 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5815 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005816 FindStringIndices(isolate,
5817 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005818 pattern->ToAsciiVector(),
5819 &indices,
5820 limit);
5821 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005822 FindStringIndices(isolate,
5823 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005824 pattern->ToUC16Vector(),
5825 &indices,
5826 limit);
5827 }
5828 }
5829 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005830
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005831 if (static_cast<uint32_t>(indices.length()) < limit) {
5832 indices.Add(subject_length);
5833 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005834
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005835 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005836
5837 // Create JSArray of substrings separated by separator.
5838 int part_count = indices.length();
5839
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005840 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005841 result->set_length(Smi::FromInt(part_count));
5842
5843 ASSERT(result->HasFastElements());
5844
5845 if (part_count == 1 && indices.at(0) == subject_length) {
5846 FixedArray::cast(result->elements())->set(0, *subject);
5847 return *result;
5848 }
5849
5850 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5851 int part_start = 0;
5852 for (int i = 0; i < part_count; i++) {
5853 HandleScope local_loop_handle;
5854 int part_end = indices.at(i);
5855 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00005856 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005857 elements->set(i, *substring);
5858 part_start = part_end + pattern_length;
5859 }
5860
5861 return *result;
5862}
5863
5864
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005865// Copies ascii characters to the given fixed array looking up
5866// one-char strings in the cache. Gives up on the first char that is
5867// not in the cache and fills the remainder with smi zeros. Returns
5868// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005869static int CopyCachedAsciiCharsToArray(Heap* heap,
5870 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005871 FixedArray* elements,
5872 int length) {
5873 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005874 FixedArray* ascii_cache = heap->single_character_string_cache();
5875 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005876 int i;
5877 for (i = 0; i < length; ++i) {
5878 Object* value = ascii_cache->get(chars[i]);
5879 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005880 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005881 elements->set(i, value, SKIP_WRITE_BARRIER);
5882 }
5883 if (i < length) {
5884 ASSERT(Smi::FromInt(0) == 0);
5885 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5886 }
5887#ifdef DEBUG
5888 for (int j = 0; j < length; ++j) {
5889 Object* element = elements->get(j);
5890 ASSERT(element == Smi::FromInt(0) ||
5891 (element->IsString() && String::cast(element)->LooksValid()));
5892 }
5893#endif
5894 return i;
5895}
5896
5897
5898// Converts a String to JSArray.
5899// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005900RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005901 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005902 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005903 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005904 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005905
5906 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005907 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005908
5909 Handle<FixedArray> elements;
5910 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005911 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005912 { MaybeObject* maybe_obj =
5913 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005914 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5915 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005916 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005917
5918 Vector<const char> chars = s->ToAsciiVector();
5919 // Note, this will initialize all elements (not only the prefix)
5920 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005921 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5922 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005923 *elements,
5924 length);
5925
5926 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005927 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5928 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005929 }
5930 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005931 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005932 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005933 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5934 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005935 }
5936 }
5937
5938#ifdef DEBUG
5939 for (int i = 0; i < length; ++i) {
5940 ASSERT(String::cast(elements->get(i))->length() == 1);
5941 }
5942#endif
5943
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005944 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005945}
5946
5947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005948RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005949 NoHandleAllocation ha;
5950 ASSERT(args.length() == 1);
5951 CONVERT_CHECKED(String, value, args[0]);
5952 return value->ToObject();
5953}
5954
5955
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005956bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005957 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005958 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005959 return char_length == 0;
5960}
5961
5962
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005963RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005964 NoHandleAllocation ha;
5965 ASSERT(args.length() == 1);
5966
5967 Object* number = args[0];
5968 RUNTIME_ASSERT(number->IsNumber());
5969
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005970 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971}
5972
5973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005974RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005975 NoHandleAllocation ha;
5976 ASSERT(args.length() == 1);
5977
5978 Object* number = args[0];
5979 RUNTIME_ASSERT(number->IsNumber());
5980
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005981 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005982}
5983
5984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005985RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986 NoHandleAllocation ha;
5987 ASSERT(args.length() == 1);
5988
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005989 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005990
5991 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5992 if (number > 0 && number <= Smi::kMaxValue) {
5993 return Smi::FromInt(static_cast<int>(number));
5994 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005995 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005996}
5997
5998
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005999RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006000 NoHandleAllocation ha;
6001 ASSERT(args.length() == 1);
6002
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006003 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006004
6005 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6006 if (number > 0 && number <= Smi::kMaxValue) {
6007 return Smi::FromInt(static_cast<int>(number));
6008 }
6009
6010 double double_value = DoubleToInteger(number);
6011 // Map both -0 and +0 to +0.
6012 if (double_value == 0) double_value = 0;
6013
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006014 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006015}
6016
6017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006018RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006019 NoHandleAllocation ha;
6020 ASSERT(args.length() == 1);
6021
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006022 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006023 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006024}
6025
6026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006027RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006028 NoHandleAllocation ha;
6029 ASSERT(args.length() == 1);
6030
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006031 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006032
6033 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6034 if (number > 0 && number <= Smi::kMaxValue) {
6035 return Smi::FromInt(static_cast<int>(number));
6036 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006037 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038}
6039
6040
ager@chromium.org870a0b62008-11-04 11:43:05 +00006041// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6042// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006043RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006044 NoHandleAllocation ha;
6045 ASSERT(args.length() == 1);
6046
6047 Object* obj = args[0];
6048 if (obj->IsSmi()) {
6049 return obj;
6050 }
6051 if (obj->IsHeapNumber()) {
6052 double value = HeapNumber::cast(obj)->value();
6053 int int_value = FastD2I(value);
6054 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6055 return Smi::FromInt(int_value);
6056 }
6057 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006058 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006059}
6060
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006062RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006063 NoHandleAllocation ha;
6064 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006065 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006066}
6067
6068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006069RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006070 NoHandleAllocation ha;
6071 ASSERT(args.length() == 2);
6072
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006073 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6074 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006075 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006076}
6077
6078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006079RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006080 NoHandleAllocation ha;
6081 ASSERT(args.length() == 2);
6082
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006083 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6084 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006085 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006086}
6087
6088
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006089RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006090 NoHandleAllocation ha;
6091 ASSERT(args.length() == 2);
6092
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006093 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6094 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006095 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006096}
6097
6098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006099RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006100 NoHandleAllocation ha;
6101 ASSERT(args.length() == 1);
6102
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006103 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006104 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006105}
6106
6107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006108RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006109 NoHandleAllocation ha;
6110 ASSERT(args.length() == 0);
6111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006112 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006113}
6114
6115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006116RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006117 NoHandleAllocation ha;
6118 ASSERT(args.length() == 2);
6119
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006120 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6121 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006122 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006123}
6124
6125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006126RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006127 NoHandleAllocation ha;
6128 ASSERT(args.length() == 2);
6129
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006130 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6131 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006132
ager@chromium.org3811b432009-10-28 14:53:37 +00006133 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006134 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006135 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006136}
6137
6138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006139RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006140 NoHandleAllocation ha;
6141 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006142 CONVERT_CHECKED(String, str1, args[0]);
6143 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006144 isolate->counters()->string_add_runtime()->Increment();
6145 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006146}
6147
6148
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006149template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006150static inline void StringBuilderConcatHelper(String* special,
6151 sinkchar* sink,
6152 FixedArray* fixed_array,
6153 int array_length) {
6154 int position = 0;
6155 for (int i = 0; i < array_length; i++) {
6156 Object* element = fixed_array->get(i);
6157 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006158 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006159 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006160 int pos;
6161 int len;
6162 if (encoded_slice > 0) {
6163 // Position and length encoded in one smi.
6164 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6165 len = StringBuilderSubstringLength::decode(encoded_slice);
6166 } else {
6167 // Position and length encoded in two smis.
6168 Object* obj = fixed_array->get(++i);
6169 ASSERT(obj->IsSmi());
6170 pos = Smi::cast(obj)->value();
6171 len = -encoded_slice;
6172 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006173 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006174 sink + position,
6175 pos,
6176 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006177 position += len;
6178 } else {
6179 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006180 int element_length = string->length();
6181 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006182 position += element_length;
6183 }
6184 }
6185}
6186
6187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006188RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006189 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006190 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006191 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006192 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006193 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006194 return Failure::OutOfMemoryException();
6195 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006196 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006197 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006198
6199 // This assumption is used by the slice encoding in one or two smis.
6200 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6201
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006202 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006204 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006205 }
6206 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006207 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006208 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006209 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006210
6211 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006212 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006213 } else if (array_length == 1) {
6214 Object* first = fixed_array->get(0);
6215 if (first->IsString()) return first;
6216 }
6217
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006218 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006219 int position = 0;
6220 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006221 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006222 Object* elt = fixed_array->get(i);
6223 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006224 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006225 int smi_value = Smi::cast(elt)->value();
6226 int pos;
6227 int len;
6228 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006229 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006230 pos = StringBuilderSubstringPosition::decode(smi_value);
6231 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006232 } else {
6233 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006234 len = -smi_value;
6235 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006236 i++;
6237 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006238 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006239 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006240 Object* next_smi = fixed_array->get(i);
6241 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006242 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006243 }
6244 pos = Smi::cast(next_smi)->value();
6245 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006246 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006247 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006248 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006249 ASSERT(pos >= 0);
6250 ASSERT(len >= 0);
6251 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006252 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006253 }
6254 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006255 } else if (elt->IsString()) {
6256 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006257 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006258 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006259 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006260 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006261 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006263 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006264 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006265 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006266 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006267 return Failure::OutOfMemoryException();
6268 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006269 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006270 }
6271
6272 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006273 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006274
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006275 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006276 { MaybeObject* maybe_object =
6277 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006278 if (!maybe_object->ToObject(&object)) return maybe_object;
6279 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006280 SeqAsciiString* answer = SeqAsciiString::cast(object);
6281 StringBuilderConcatHelper(special,
6282 answer->GetChars(),
6283 fixed_array,
6284 array_length);
6285 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006286 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006287 { MaybeObject* maybe_object =
6288 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006289 if (!maybe_object->ToObject(&object)) return maybe_object;
6290 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006291 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6292 StringBuilderConcatHelper(special,
6293 answer->GetChars(),
6294 fixed_array,
6295 array_length);
6296 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006297 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006298}
6299
6300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006301RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006302 NoHandleAllocation ha;
6303 ASSERT(args.length() == 3);
6304 CONVERT_CHECKED(JSArray, array, args[0]);
6305 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006306 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006307 return Failure::OutOfMemoryException();
6308 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006309 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006310 CONVERT_CHECKED(String, separator, args[2]);
6311
6312 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006313 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006314 }
6315 FixedArray* fixed_array = FixedArray::cast(array->elements());
6316 if (fixed_array->length() < array_length) {
6317 array_length = fixed_array->length();
6318 }
6319
6320 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006321 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006322 } else if (array_length == 1) {
6323 Object* first = fixed_array->get(0);
6324 if (first->IsString()) return first;
6325 }
6326
6327 int separator_length = separator->length();
6328 int max_nof_separators =
6329 (String::kMaxLength + separator_length - 1) / separator_length;
6330 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006331 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006332 return Failure::OutOfMemoryException();
6333 }
6334 int length = (array_length - 1) * separator_length;
6335 for (int i = 0; i < array_length; i++) {
6336 Object* element_obj = fixed_array->get(i);
6337 if (!element_obj->IsString()) {
6338 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006339 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006340 }
6341 String* element = String::cast(element_obj);
6342 int increment = element->length();
6343 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006344 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006345 return Failure::OutOfMemoryException();
6346 }
6347 length += increment;
6348 }
6349
6350 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006351 { MaybeObject* maybe_object =
6352 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006353 if (!maybe_object->ToObject(&object)) return maybe_object;
6354 }
6355 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6356
6357 uc16* sink = answer->GetChars();
6358#ifdef DEBUG
6359 uc16* end = sink + length;
6360#endif
6361
6362 String* first = String::cast(fixed_array->get(0));
6363 int first_length = first->length();
6364 String::WriteToFlat(first, sink, 0, first_length);
6365 sink += first_length;
6366
6367 for (int i = 1; i < array_length; i++) {
6368 ASSERT(sink + separator_length <= end);
6369 String::WriteToFlat(separator, sink, 0, separator_length);
6370 sink += separator_length;
6371
6372 String* element = String::cast(fixed_array->get(i));
6373 int element_length = element->length();
6374 ASSERT(sink + element_length <= end);
6375 String::WriteToFlat(element, sink, 0, element_length);
6376 sink += element_length;
6377 }
6378 ASSERT(sink == end);
6379
6380 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6381 return answer;
6382}
6383
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006384template <typename Char>
6385static void JoinSparseArrayWithSeparator(FixedArray* elements,
6386 int elements_length,
6387 uint32_t array_length,
6388 String* separator,
6389 Vector<Char> buffer) {
6390 int previous_separator_position = 0;
6391 int separator_length = separator->length();
6392 int cursor = 0;
6393 for (int i = 0; i < elements_length; i += 2) {
6394 int position = NumberToInt32(elements->get(i));
6395 String* string = String::cast(elements->get(i + 1));
6396 int string_length = string->length();
6397 if (string->length() > 0) {
6398 while (previous_separator_position < position) {
6399 String::WriteToFlat<Char>(separator, &buffer[cursor],
6400 0, separator_length);
6401 cursor += separator_length;
6402 previous_separator_position++;
6403 }
6404 String::WriteToFlat<Char>(string, &buffer[cursor],
6405 0, string_length);
6406 cursor += string->length();
6407 }
6408 }
6409 if (separator_length > 0) {
6410 // Array length must be representable as a signed 32-bit number,
6411 // otherwise the total string length would have been too large.
6412 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6413 int last_array_index = static_cast<int>(array_length - 1);
6414 while (previous_separator_position < last_array_index) {
6415 String::WriteToFlat<Char>(separator, &buffer[cursor],
6416 0, separator_length);
6417 cursor += separator_length;
6418 previous_separator_position++;
6419 }
6420 }
6421 ASSERT(cursor <= buffer.length());
6422}
6423
6424
6425RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6426 NoHandleAllocation ha;
6427 ASSERT(args.length() == 3);
6428 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6429 RUNTIME_ASSERT(elements_array->HasFastElements());
6430 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6431 CONVERT_CHECKED(String, separator, args[2]);
6432 // elements_array is fast-mode JSarray of alternating positions
6433 // (increasing order) and strings.
6434 // array_length is length of original array (used to add separators);
6435 // separator is string to put between elements. Assumed to be non-empty.
6436
6437 // Find total length of join result.
6438 int string_length = 0;
6439 bool is_ascii = true;
6440 int max_string_length = SeqAsciiString::kMaxLength;
6441 bool overflow = false;
6442 CONVERT_NUMBER_CHECKED(int, elements_length,
6443 Int32, elements_array->length());
6444 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6445 FixedArray* elements = FixedArray::cast(elements_array->elements());
6446 for (int i = 0; i < elements_length; i += 2) {
6447 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6448 CONVERT_CHECKED(String, string, elements->get(i + 1));
6449 int length = string->length();
6450 if (is_ascii && !string->IsAsciiRepresentation()) {
6451 is_ascii = false;
6452 max_string_length = SeqTwoByteString::kMaxLength;
6453 }
6454 if (length > max_string_length ||
6455 max_string_length - length < string_length) {
6456 overflow = true;
6457 break;
6458 }
6459 string_length += length;
6460 }
6461 int separator_length = separator->length();
6462 if (!overflow && separator_length > 0) {
6463 if (array_length <= 0x7fffffffu) {
6464 int separator_count = static_cast<int>(array_length) - 1;
6465 int remaining_length = max_string_length - string_length;
6466 if ((remaining_length / separator_length) >= separator_count) {
6467 string_length += separator_length * (array_length - 1);
6468 } else {
6469 // Not room for the separators within the maximal string length.
6470 overflow = true;
6471 }
6472 } else {
6473 // Nonempty separator and at least 2^31-1 separators necessary
6474 // means that the string is too large to create.
6475 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6476 overflow = true;
6477 }
6478 }
6479 if (overflow) {
6480 // Throw OutOfMemory exception for creating too large a string.
6481 V8::FatalProcessOutOfMemory("Array join result too large.");
6482 }
6483
6484 if (is_ascii) {
6485 MaybeObject* result_allocation =
6486 isolate->heap()->AllocateRawAsciiString(string_length);
6487 if (result_allocation->IsFailure()) return result_allocation;
6488 SeqAsciiString* result_string =
6489 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6490 JoinSparseArrayWithSeparator<char>(elements,
6491 elements_length,
6492 array_length,
6493 separator,
6494 Vector<char>(result_string->GetChars(),
6495 string_length));
6496 return result_string;
6497 } else {
6498 MaybeObject* result_allocation =
6499 isolate->heap()->AllocateRawTwoByteString(string_length);
6500 if (result_allocation->IsFailure()) return result_allocation;
6501 SeqTwoByteString* result_string =
6502 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6503 JoinSparseArrayWithSeparator<uc16>(elements,
6504 elements_length,
6505 array_length,
6506 separator,
6507 Vector<uc16>(result_string->GetChars(),
6508 string_length));
6509 return result_string;
6510 }
6511}
6512
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006514RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515 NoHandleAllocation ha;
6516 ASSERT(args.length() == 2);
6517
6518 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6519 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006520 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006521}
6522
6523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006524RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525 NoHandleAllocation ha;
6526 ASSERT(args.length() == 2);
6527
6528 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6529 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006530 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006531}
6532
6533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006534RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006535 NoHandleAllocation ha;
6536 ASSERT(args.length() == 2);
6537
6538 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6539 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006540 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006541}
6542
6543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006544RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006545 NoHandleAllocation ha;
6546 ASSERT(args.length() == 1);
6547
6548 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006549 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550}
6551
6552
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006553RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006554 NoHandleAllocation ha;
6555 ASSERT(args.length() == 2);
6556
6557 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6558 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006559 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006560}
6561
6562
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006563RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006564 NoHandleAllocation ha;
6565 ASSERT(args.length() == 2);
6566
6567 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6568 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006569 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006570}
6571
6572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006573RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006574 NoHandleAllocation ha;
6575 ASSERT(args.length() == 2);
6576
6577 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6578 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006579 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006580}
6581
6582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006583RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006584 NoHandleAllocation ha;
6585 ASSERT(args.length() == 2);
6586
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006587 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6588 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6590 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6591 if (x == y) return Smi::FromInt(EQUAL);
6592 Object* result;
6593 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6594 result = Smi::FromInt(EQUAL);
6595 } else {
6596 result = Smi::FromInt(NOT_EQUAL);
6597 }
6598 return result;
6599}
6600
6601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006602RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006603 NoHandleAllocation ha;
6604 ASSERT(args.length() == 2);
6605
6606 CONVERT_CHECKED(String, x, args[0]);
6607 CONVERT_CHECKED(String, y, args[1]);
6608
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006609 bool not_equal = !x->Equals(y);
6610 // This is slightly convoluted because the value that signifies
6611 // equality is 0 and inequality is 1 so we have to negate the result
6612 // from String::Equals.
6613 ASSERT(not_equal == 0 || not_equal == 1);
6614 STATIC_CHECK(EQUAL == 0);
6615 STATIC_CHECK(NOT_EQUAL == 1);
6616 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006617}
6618
6619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006620RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006621 NoHandleAllocation ha;
6622 ASSERT(args.length() == 3);
6623
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006624 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6625 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006626 if (isnan(x) || isnan(y)) return args[2];
6627 if (x == y) return Smi::FromInt(EQUAL);
6628 if (isless(x, y)) return Smi::FromInt(LESS);
6629 return Smi::FromInt(GREATER);
6630}
6631
6632
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006633// Compare two Smis as if they were converted to strings and then
6634// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006635RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006636 NoHandleAllocation ha;
6637 ASSERT(args.length() == 2);
6638
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006639 // Extract the integer values from the Smis.
6640 CONVERT_CHECKED(Smi, x, args[0]);
6641 CONVERT_CHECKED(Smi, y, args[1]);
6642 int x_value = x->value();
6643 int y_value = y->value();
6644
6645 // If the integers are equal so are the string representations.
6646 if (x_value == y_value) return Smi::FromInt(EQUAL);
6647
6648 // If one of the integers are zero the normal integer order is the
6649 // same as the lexicographic order of the string representations.
6650 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6651
ager@chromium.org32912102009-01-16 10:38:43 +00006652 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006653 // smallest because the char code of '-' is less than the char code
6654 // of any digit. Otherwise, we make both values positive.
6655 if (x_value < 0 || y_value < 0) {
6656 if (y_value >= 0) return Smi::FromInt(LESS);
6657 if (x_value >= 0) return Smi::FromInt(GREATER);
6658 x_value = -x_value;
6659 y_value = -y_value;
6660 }
6661
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006662 // Arrays for the individual characters of the two Smis. Smis are
6663 // 31 bit integers and 10 decimal digits are therefore enough.
6664 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6665 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6666 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6667
6668
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006669 // Convert the integers to arrays of their decimal digits.
6670 int x_index = 0;
6671 int y_index = 0;
6672 while (x_value > 0) {
6673 x_elms[x_index++] = x_value % 10;
6674 x_value /= 10;
6675 }
6676 while (y_value > 0) {
6677 y_elms[y_index++] = y_value % 10;
6678 y_value /= 10;
6679 }
6680
6681 // Loop through the arrays of decimal digits finding the first place
6682 // where they differ.
6683 while (--x_index >= 0 && --y_index >= 0) {
6684 int diff = x_elms[x_index] - y_elms[y_index];
6685 if (diff != 0) return Smi::FromInt(diff);
6686 }
6687
6688 // If one array is a suffix of the other array, the longest array is
6689 // the representation of the largest of the Smis in the
6690 // lexicographic ordering.
6691 return Smi::FromInt(x_index - y_index);
6692}
6693
6694
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006695static Object* StringInputBufferCompare(RuntimeState* state,
6696 String* x,
6697 String* y) {
6698 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6699 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006700 bufx.Reset(x);
6701 bufy.Reset(y);
6702 while (bufx.has_more() && bufy.has_more()) {
6703 int d = bufx.GetNext() - bufy.GetNext();
6704 if (d < 0) return Smi::FromInt(LESS);
6705 else if (d > 0) return Smi::FromInt(GREATER);
6706 }
6707
6708 // x is (non-trivial) prefix of y:
6709 if (bufy.has_more()) return Smi::FromInt(LESS);
6710 // y is prefix of x:
6711 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6712}
6713
6714
6715static Object* FlatStringCompare(String* x, String* y) {
6716 ASSERT(x->IsFlat());
6717 ASSERT(y->IsFlat());
6718 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6719 int prefix_length = x->length();
6720 if (y->length() < prefix_length) {
6721 prefix_length = y->length();
6722 equal_prefix_result = Smi::FromInt(GREATER);
6723 } else if (y->length() > prefix_length) {
6724 equal_prefix_result = Smi::FromInt(LESS);
6725 }
6726 int r;
6727 if (x->IsAsciiRepresentation()) {
6728 Vector<const char> x_chars = x->ToAsciiVector();
6729 if (y->IsAsciiRepresentation()) {
6730 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006731 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006732 } else {
6733 Vector<const uc16> y_chars = y->ToUC16Vector();
6734 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6735 }
6736 } else {
6737 Vector<const uc16> x_chars = x->ToUC16Vector();
6738 if (y->IsAsciiRepresentation()) {
6739 Vector<const char> y_chars = y->ToAsciiVector();
6740 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6741 } else {
6742 Vector<const uc16> y_chars = y->ToUC16Vector();
6743 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6744 }
6745 }
6746 Object* result;
6747 if (r == 0) {
6748 result = equal_prefix_result;
6749 } else {
6750 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6751 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006752 ASSERT(result ==
6753 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006754 return result;
6755}
6756
6757
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006758RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006759 NoHandleAllocation ha;
6760 ASSERT(args.length() == 2);
6761
6762 CONVERT_CHECKED(String, x, args[0]);
6763 CONVERT_CHECKED(String, y, args[1]);
6764
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006765 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006766
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006767 // A few fast case tests before we flatten.
6768 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006769 if (y->length() == 0) {
6770 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006771 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006772 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006773 return Smi::FromInt(LESS);
6774 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006775
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006776 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006777 if (d < 0) return Smi::FromInt(LESS);
6778 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006779
lrn@chromium.org303ada72010-10-27 09:33:13 +00006780 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006781 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006782 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6783 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006784 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006785 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6786 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006787
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006788 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006789 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006790}
6791
6792
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006793RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
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_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006797
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006798 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006799 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006800}
6801
6802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006803RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006804 NoHandleAllocation ha;
6805 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006806 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006807
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006808 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006809 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006810}
6811
6812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006813RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006814 NoHandleAllocation ha;
6815 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006816 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006817
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006818 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006819 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006820}
6821
6822
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006823static const double kPiDividedBy4 = 0.78539816339744830962;
6824
6825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006826RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006827 NoHandleAllocation ha;
6828 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006829 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006830
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006831 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6832 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006833 double result;
6834 if (isinf(x) && isinf(y)) {
6835 // Make sure that the result in case of two infinite arguments
6836 // is a multiple of Pi / 4. The sign of the result is determined
6837 // by the first argument (x) and the sign of the second argument
6838 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006839 int multiplier = (x < 0) ? -1 : 1;
6840 if (y < 0) multiplier *= 3;
6841 result = multiplier * kPiDividedBy4;
6842 } else {
6843 result = atan2(x, y);
6844 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006845 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006846}
6847
6848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006849RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006850 NoHandleAllocation ha;
6851 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006852 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006853
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006854 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006855 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006856}
6857
6858
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006859RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006860 NoHandleAllocation ha;
6861 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006862 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006863
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006864 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006865 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006866}
6867
6868
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006869RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006870 NoHandleAllocation ha;
6871 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006872 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006873
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006874 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006875 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006876}
6877
6878
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006879RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006880 NoHandleAllocation ha;
6881 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006882 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006883
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006884 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006885 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006886}
6887
6888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006889RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006890 NoHandleAllocation ha;
6891 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006892 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006893
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006894 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006895 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006896}
6897
6898
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006899RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006900 NoHandleAllocation ha;
6901 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006902 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006903
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006904 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006905
6906 // If the second argument is a smi, it is much faster to call the
6907 // custom powi() function than the generic pow().
6908 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006909 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006910 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006911 }
6912
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006913 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006914 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006915}
6916
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006917// Fast version of Math.pow if we know that y is not an integer and
6918// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006919RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006920 NoHandleAllocation ha;
6921 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006922 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6923 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006924 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006925 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006926 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006927 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006928 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006929 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006930 }
6931}
6932
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006934RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006935 NoHandleAllocation ha;
6936 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006937 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006938
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006939 if (!args[0]->IsHeapNumber()) {
6940 // Must be smi. Return the argument unchanged for all the other types
6941 // to make fuzz-natives test happy.
6942 return args[0];
6943 }
6944
6945 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6946
6947 double value = number->value();
6948 int exponent = number->get_exponent();
6949 int sign = number->get_sign();
6950
danno@chromium.org160a7b02011-04-18 15:51:38 +00006951 if (exponent < -1) {
6952 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6953 if (sign) return isolate->heap()->minus_zero_value();
6954 return Smi::FromInt(0);
6955 }
6956
6957 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6958 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6959 // agument holds for 32-bit smis).
6960 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006961 return Smi::FromInt(static_cast<int>(value + 0.5));
6962 }
6963
6964 // If the magnitude is big enough, there's no place for fraction part. If we
6965 // try to add 0.5 to this number, 1.0 will be added instead.
6966 if (exponent >= 52) {
6967 return number;
6968 }
6969
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006970 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006971
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006972 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006973 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006974}
6975
6976
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006977RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006978 NoHandleAllocation ha;
6979 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006980 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006982 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006983 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006984}
6985
6986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006987RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006988 NoHandleAllocation ha;
6989 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006990 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006991
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006992 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006993 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006994}
6995
6996
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006997RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006998 NoHandleAllocation ha;
6999 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007000 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007001
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007002 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007003 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007004}
7005
7006
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007007static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007008 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7009 181, 212, 243, 273, 304, 334};
7010 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7011 182, 213, 244, 274, 305, 335};
7012
7013 year += month / 12;
7014 month %= 12;
7015 if (month < 0) {
7016 year--;
7017 month += 12;
7018 }
7019
7020 ASSERT(month >= 0);
7021 ASSERT(month < 12);
7022
7023 // year_delta is an arbitrary number such that:
7024 // a) year_delta = -1 (mod 400)
7025 // b) year + year_delta > 0 for years in the range defined by
7026 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7027 // Jan 1 1970. This is required so that we don't run into integer
7028 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007029 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007030 // operations.
7031 static const int year_delta = 399999;
7032 static const int base_day = 365 * (1970 + year_delta) +
7033 (1970 + year_delta) / 4 -
7034 (1970 + year_delta) / 100 +
7035 (1970 + year_delta) / 400;
7036
7037 int year1 = year + year_delta;
7038 int day_from_year = 365 * year1 +
7039 year1 / 4 -
7040 year1 / 100 +
7041 year1 / 400 -
7042 base_day;
7043
7044 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007045 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007046 }
7047
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007048 return day_from_year + day_from_month_leap[month] + day - 1;
7049}
7050
7051
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007052RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007053 NoHandleAllocation ha;
7054 ASSERT(args.length() == 3);
7055
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007056 CONVERT_SMI_ARG_CHECKED(year, 0);
7057 CONVERT_SMI_ARG_CHECKED(month, 1);
7058 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007059
7060 return Smi::FromInt(MakeDay(year, month, date));
7061}
7062
7063
7064static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7065static const int kDaysIn4Years = 4 * 365 + 1;
7066static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7067static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7068static const int kDays1970to2000 = 30 * 365 + 7;
7069static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7070 kDays1970to2000;
7071static const int kYearsOffset = 400000;
7072
7073static const char kDayInYear[] = {
7074 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7075 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7076 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7077 22, 23, 24, 25, 26, 27, 28,
7078 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7079 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7080 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7081 22, 23, 24, 25, 26, 27, 28, 29, 30,
7082 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7083 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7084 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7085 22, 23, 24, 25, 26, 27, 28, 29, 30,
7086 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7087 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7088 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7089 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7090 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7091 22, 23, 24, 25, 26, 27, 28, 29, 30,
7092 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7093 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7094 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7095 22, 23, 24, 25, 26, 27, 28, 29, 30,
7096 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7097 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7098
7099 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7100 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7101 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7102 22, 23, 24, 25, 26, 27, 28,
7103 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7104 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7105 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7106 22, 23, 24, 25, 26, 27, 28, 29, 30,
7107 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7108 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7109 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7110 22, 23, 24, 25, 26, 27, 28, 29, 30,
7111 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7112 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7113 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7114 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7115 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7116 22, 23, 24, 25, 26, 27, 28, 29, 30,
7117 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7118 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7119 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7120 22, 23, 24, 25, 26, 27, 28, 29, 30,
7121 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7122 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7123
7124 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7125 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7126 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7127 22, 23, 24, 25, 26, 27, 28, 29,
7128 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7129 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7130 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7131 22, 23, 24, 25, 26, 27, 28, 29, 30,
7132 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7133 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7134 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7135 22, 23, 24, 25, 26, 27, 28, 29, 30,
7136 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7137 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7138 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7139 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7140 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7141 22, 23, 24, 25, 26, 27, 28, 29, 30,
7142 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7143 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7144 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7145 22, 23, 24, 25, 26, 27, 28, 29, 30,
7146 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7147 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7148
7149 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7150 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7151 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7152 22, 23, 24, 25, 26, 27, 28,
7153 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7154 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7155 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7156 22, 23, 24, 25, 26, 27, 28, 29, 30,
7157 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7158 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7159 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7160 22, 23, 24, 25, 26, 27, 28, 29, 30,
7161 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7162 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7163 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7164 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7165 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7166 22, 23, 24, 25, 26, 27, 28, 29, 30,
7167 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7168 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7169 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7170 22, 23, 24, 25, 26, 27, 28, 29, 30,
7171 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7172 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7173
7174static const char kMonthInYear[] = {
7175 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,
7176 0, 0, 0, 0, 0, 0,
7177 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,
7178 1, 1, 1,
7179 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,
7180 2, 2, 2, 2, 2, 2,
7181 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,
7182 3, 3, 3, 3, 3,
7183 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,
7184 4, 4, 4, 4, 4, 4,
7185 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,
7186 5, 5, 5, 5, 5,
7187 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,
7188 6, 6, 6, 6, 6, 6,
7189 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,
7190 7, 7, 7, 7, 7, 7,
7191 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,
7192 8, 8, 8, 8, 8,
7193 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,
7194 9, 9, 9, 9, 9, 9,
7195 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7196 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7197 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7198 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7199
7200 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,
7201 0, 0, 0, 0, 0, 0,
7202 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,
7203 1, 1, 1,
7204 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,
7205 2, 2, 2, 2, 2, 2,
7206 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,
7207 3, 3, 3, 3, 3,
7208 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,
7209 4, 4, 4, 4, 4, 4,
7210 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,
7211 5, 5, 5, 5, 5,
7212 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,
7213 6, 6, 6, 6, 6, 6,
7214 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,
7215 7, 7, 7, 7, 7, 7,
7216 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,
7217 8, 8, 8, 8, 8,
7218 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,
7219 9, 9, 9, 9, 9, 9,
7220 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7221 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7222 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7223 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7224
7225 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,
7226 0, 0, 0, 0, 0, 0,
7227 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,
7228 1, 1, 1, 1,
7229 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,
7230 2, 2, 2, 2, 2, 2,
7231 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,
7232 3, 3, 3, 3, 3,
7233 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,
7234 4, 4, 4, 4, 4, 4,
7235 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,
7236 5, 5, 5, 5, 5,
7237 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,
7238 6, 6, 6, 6, 6, 6,
7239 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,
7240 7, 7, 7, 7, 7, 7,
7241 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,
7242 8, 8, 8, 8, 8,
7243 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,
7244 9, 9, 9, 9, 9, 9,
7245 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7246 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7247 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7248 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7249
7250 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,
7251 0, 0, 0, 0, 0, 0,
7252 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,
7253 1, 1, 1,
7254 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,
7255 2, 2, 2, 2, 2, 2,
7256 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,
7257 3, 3, 3, 3, 3,
7258 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,
7259 4, 4, 4, 4, 4, 4,
7260 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,
7261 5, 5, 5, 5, 5,
7262 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,
7263 6, 6, 6, 6, 6, 6,
7264 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,
7265 7, 7, 7, 7, 7, 7,
7266 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,
7267 8, 8, 8, 8, 8,
7268 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,
7269 9, 9, 9, 9, 9, 9,
7270 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7271 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7272 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7273 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7274
7275
7276// This function works for dates from 1970 to 2099.
7277static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007278 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007279#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007280 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007281#endif
7282
7283 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7284 date %= kDaysIn4Years;
7285
7286 month = kMonthInYear[date];
7287 day = kDayInYear[date];
7288
7289 ASSERT(MakeDay(year, month, day) == save_date);
7290}
7291
7292
7293static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007294 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007295#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007296 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007297#endif
7298
7299 date += kDaysOffset;
7300 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7301 date %= kDaysIn400Years;
7302
7303 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7304
7305 date--;
7306 int yd1 = date / kDaysIn100Years;
7307 date %= kDaysIn100Years;
7308 year += 100 * yd1;
7309
7310 date++;
7311 int yd2 = date / kDaysIn4Years;
7312 date %= kDaysIn4Years;
7313 year += 4 * yd2;
7314
7315 date--;
7316 int yd3 = date / 365;
7317 date %= 365;
7318 year += yd3;
7319
7320 bool is_leap = (!yd1 || yd2) && !yd3;
7321
7322 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007323 ASSERT(is_leap || (date >= 0));
7324 ASSERT((date < 365) || (is_leap && (date < 366)));
7325 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7326 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7327 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007328
7329 if (is_leap) {
7330 day = kDayInYear[2*365 + 1 + date];
7331 month = kMonthInYear[2*365 + 1 + date];
7332 } else {
7333 day = kDayInYear[date];
7334 month = kMonthInYear[date];
7335 }
7336
7337 ASSERT(MakeDay(year, month, day) == save_date);
7338}
7339
7340
7341static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007342 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007343 if (date >= 0 && date < 32 * kDaysIn4Years) {
7344 DateYMDFromTimeAfter1970(date, year, month, day);
7345 } else {
7346 DateYMDFromTimeSlow(date, year, month, day);
7347 }
7348}
7349
7350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007351RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007352 NoHandleAllocation ha;
7353 ASSERT(args.length() == 2);
7354
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007355 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007356 CONVERT_CHECKED(JSArray, res_array, args[1]);
7357
7358 int year, month, day;
7359 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007361 RUNTIME_ASSERT(res_array->elements()->map() ==
7362 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007363 FixedArray* elms = FixedArray::cast(res_array->elements());
7364 RUNTIME_ASSERT(elms->length() == 3);
7365
7366 elms->set(0, Smi::FromInt(year));
7367 elms->set(1, Smi::FromInt(month));
7368 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007369
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007370 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007371}
7372
7373
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007374RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007375 HandleScope scope(isolate);
7376 ASSERT(args.length() == 3);
7377
7378 Handle<JSFunction> callee = args.at<JSFunction>(0);
7379 Object** parameters = reinterpret_cast<Object**>(args[1]);
7380 const int argument_count = Smi::cast(args[2])->value();
7381
7382 Handle<JSObject> result =
7383 isolate->factory()->NewArgumentsObject(callee, argument_count);
7384 // Allocate the elements if needed.
7385 int parameter_count = callee->shared()->formal_parameter_count();
7386 if (argument_count > 0) {
7387 if (parameter_count > 0) {
7388 int mapped_count = Min(argument_count, parameter_count);
7389 Handle<FixedArray> parameter_map =
7390 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7391 parameter_map->set_map(
7392 isolate->heap()->non_strict_arguments_elements_map());
7393
7394 Handle<Map> old_map(result->map());
7395 Handle<Map> new_map =
7396 isolate->factory()->CopyMapDropTransitions(old_map);
7397 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7398
7399 result->set_map(*new_map);
7400 result->set_elements(*parameter_map);
7401
7402 // Store the context and the arguments array at the beginning of the
7403 // parameter map.
7404 Handle<Context> context(isolate->context());
7405 Handle<FixedArray> arguments =
7406 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7407 parameter_map->set(0, *context);
7408 parameter_map->set(1, *arguments);
7409
7410 // Loop over the actual parameters backwards.
7411 int index = argument_count - 1;
7412 while (index >= mapped_count) {
7413 // These go directly in the arguments array and have no
7414 // corresponding slot in the parameter map.
7415 arguments->set(index, *(parameters - index - 1));
7416 --index;
7417 }
7418
7419 ScopeInfo<> scope_info(callee->shared()->scope_info());
7420 while (index >= 0) {
7421 // Detect duplicate names to the right in the parameter list.
7422 Handle<String> name = scope_info.parameter_name(index);
7423 int context_slot_count = scope_info.number_of_context_slots();
7424 bool duplicate = false;
7425 for (int j = index + 1; j < parameter_count; ++j) {
7426 if (scope_info.parameter_name(j).is_identical_to(name)) {
7427 duplicate = true;
7428 break;
7429 }
7430 }
7431
7432 if (duplicate) {
7433 // This goes directly in the arguments array with a hole in the
7434 // parameter map.
7435 arguments->set(index, *(parameters - index - 1));
7436 parameter_map->set_the_hole(index + 2);
7437 } else {
7438 // The context index goes in the parameter map with a hole in the
7439 // arguments array.
7440 int context_index = -1;
7441 for (int j = Context::MIN_CONTEXT_SLOTS;
7442 j < context_slot_count;
7443 ++j) {
7444 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7445 context_index = j;
7446 break;
7447 }
7448 }
7449 ASSERT(context_index >= 0);
7450 arguments->set_the_hole(index);
7451 parameter_map->set(index + 2, Smi::FromInt(context_index));
7452 }
7453
7454 --index;
7455 }
7456 } else {
7457 // If there is no aliasing, the arguments object elements are not
7458 // special in any way.
7459 Handle<FixedArray> elements =
7460 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7461 result->set_elements(*elements);
7462 for (int i = 0; i < argument_count; ++i) {
7463 elements->set(i, *(parameters - i - 1));
7464 }
7465 }
7466 }
7467 return *result;
7468}
7469
7470
7471RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007472 NoHandleAllocation ha;
7473 ASSERT(args.length() == 3);
7474
7475 JSFunction* callee = JSFunction::cast(args[0]);
7476 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007477 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007478
lrn@chromium.org303ada72010-10-27 09:33:13 +00007479 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007480 { MaybeObject* maybe_result =
7481 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007482 if (!maybe_result->ToObject(&result)) return maybe_result;
7483 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007484 // Allocate the elements if needed.
7485 if (length > 0) {
7486 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007487 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007488 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007489 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7490 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007491
7492 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007493 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007494 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007495 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007496
7497 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007498 for (int i = 0; i < length; i++) {
7499 array->set(i, *--parameters, mode);
7500 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007501 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007502 }
7503 return result;
7504}
7505
7506
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007507RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007508 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007509 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007510 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007511 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007512 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007513
whesse@chromium.org7b260152011-06-20 15:33:18 +00007514 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007515 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007516 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007517 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007518 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7519 context,
7520 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007521 return *result;
7522}
7523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007524
7525static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7526 int* total_argc) {
7527 // Find frame containing arguments passed to the caller.
7528 JavaScriptFrameIterator it;
7529 JavaScriptFrame* frame = it.frame();
7530 List<JSFunction*> functions(2);
7531 frame->GetFunctions(&functions);
7532 if (functions.length() > 1) {
7533 int inlined_frame_index = functions.length() - 1;
7534 JSFunction* inlined_function = functions[inlined_frame_index];
7535 int args_count = inlined_function->shared()->formal_parameter_count();
7536 ScopedVector<SlotRef> args_slots(args_count);
7537 SlotRef::ComputeSlotMappingForArguments(frame,
7538 inlined_frame_index,
7539 &args_slots);
7540
7541 *total_argc = bound_argc + args_count;
7542 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7543 for (int i = 0; i < args_count; i++) {
7544 Handle<Object> val = args_slots[i].GetValue();
7545 param_data[bound_argc + i] = val.location();
7546 }
7547 return param_data;
7548 } else {
7549 it.AdvanceToArgumentsFrame();
7550 frame = it.frame();
7551 int args_count = frame->ComputeParametersCount();
7552
7553 *total_argc = bound_argc + args_count;
7554 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7555 for (int i = 0; i < args_count; i++) {
7556 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7557 param_data[bound_argc + i] = val.location();
7558 }
7559 return param_data;
7560 }
7561}
7562
7563
7564RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007565 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007566 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007567 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007568 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007569
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007570 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007571 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007572 int bound_argc = 0;
7573 if (!args[1]->IsNull()) {
7574 CONVERT_ARG_CHECKED(JSArray, params, 1);
7575 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007576 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007577 bound_argc = Smi::cast(params->length())->value();
7578 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007579
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007580 int total_argc = 0;
7581 SmartPointer<Object**> param_data =
7582 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007583 for (int i = 0; i < bound_argc; i++) {
7584 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007585 param_data[i] = val.location();
7586 }
7587
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007588 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007589 Handle<Object> result =
7590 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007591 if (exception) {
7592 return Failure::Exception();
7593 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007594
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007595 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007596 return *result;
7597}
7598
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007599
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007600static void TrySettingInlineConstructStub(Isolate* isolate,
7601 Handle<JSFunction> function) {
7602 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007603 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007604 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007605 }
7606 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007607 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007608 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007609 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007610 function->shared()->set_construct_stub(
7611 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007612 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007613 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007614}
7615
7616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007617RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007618 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007619 ASSERT(args.length() == 1);
7620
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007621 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007622
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007623 // If the constructor isn't a proper function we throw a type error.
7624 if (!constructor->IsJSFunction()) {
7625 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7626 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007627 isolate->factory()->NewTypeError("not_constructor", arguments);
7628 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007629 }
7630
7631 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007632
7633 // If function should not have prototype, construction is not allowed. In this
7634 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007635 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007636 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7637 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007638 isolate->factory()->NewTypeError("not_constructor", arguments);
7639 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007640 }
7641
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007642#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007643 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007644 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007645 if (debug->StepInActive()) {
7646 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007647 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007648#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007649
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007650 if (function->has_initial_map()) {
7651 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007652 // The 'Function' function ignores the receiver object when
7653 // called using 'new' and creates a new JSFunction object that
7654 // is returned. The receiver object is only used for error
7655 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007656 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007657 // allocate JSFunctions since it does not properly initialize
7658 // the shared part of the function. Since the receiver is
7659 // ignored anyway, we use the global object as the receiver
7660 // instead of a new JSFunction object. This way, errors are
7661 // reported the same way whether or not 'Function' is called
7662 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007663 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007664 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007665 }
7666
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007667 // The function should be compiled for the optimization hints to be
7668 // available. We cannot use EnsureCompiled because that forces a
7669 // compilation through the shared function info which makes it
7670 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007671 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007672 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007673
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007674 if (!function->has_initial_map() &&
7675 shared->IsInobjectSlackTrackingInProgress()) {
7676 // The tracking is already in progress for another function. We can only
7677 // track one initial_map at a time, so we force the completion before the
7678 // function is called as a constructor for the first time.
7679 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007680 }
7681
7682 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007683 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7684 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007685 // Delay setting the stub if inobject slack tracking is in progress.
7686 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007687 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007688 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007689
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007690 isolate->counters()->constructed_objects()->Increment();
7691 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007692
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007693 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007694}
7695
7696
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007697RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007698 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007699 ASSERT(args.length() == 1);
7700
7701 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7702 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007703 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007704
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007705 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007706}
7707
7708
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007709RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007710 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007711 ASSERT(args.length() == 1);
7712
7713 Handle<JSFunction> function = args.at<JSFunction>(0);
7714#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007715 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007716 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007717 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007718 PrintF("]\n");
7719 }
7720#endif
7721
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007722 // Compile the target function. Here we compile using CompileLazyInLoop in
7723 // order to get the optimized version. This helps code like delta-blue
7724 // that calls performance-critical routines through constructors. A
7725 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7726 // direct call. Since the in-loop tracking takes place through CallICs
7727 // this means that things called through constructors are never known to
7728 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007729 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007730 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731 return Failure::Exception();
7732 }
7733
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007734 // All done. Return the compiled code.
7735 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007736 return function->code();
7737}
7738
7739
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007740RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007741 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007742 ASSERT(args.length() == 1);
7743 Handle<JSFunction> function = args.at<JSFunction>(0);
7744 // If the function is not optimizable or debugger is active continue using the
7745 // code from the full compiler.
7746 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007747 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007748 if (FLAG_trace_opt) {
7749 PrintF("[failed to optimize ");
7750 function->PrintName();
7751 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7752 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007753 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007754 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007755 function->ReplaceCode(function->shared()->code());
7756 return function->code();
7757 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007758 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007759 return function->code();
7760 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007761 if (FLAG_trace_opt) {
7762 PrintF("[failed to optimize ");
7763 function->PrintName();
7764 PrintF(": optimized compilation failed]\n");
7765 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007766 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007767 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007768}
7769
7770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007771RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007772 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007773 ASSERT(args.length() == 1);
7774 RUNTIME_ASSERT(args[0]->IsSmi());
7775 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007776 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007777 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7778 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007779 int frames = deoptimizer->output_count();
7780
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007781 deoptimizer->MaterializeHeapNumbers();
7782 delete deoptimizer;
7783
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007784 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007785 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007786 for (int i = 0; i < frames - 1; i++) it.Advance();
7787 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007788
7789 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007790 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007791 Handle<Object> arguments;
7792 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007793 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007794 if (arguments.is_null()) {
7795 // FunctionGetArguments can't throw an exception, so cast away the
7796 // doubt with an assert.
7797 arguments = Handle<Object>(
7798 Accessors::FunctionGetArguments(*function,
7799 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007800 ASSERT(*arguments != isolate->heap()->null_value());
7801 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007802 }
7803 frame->SetExpression(i, *arguments);
7804 }
7805 }
7806
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007807 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007808 if (type == Deoptimizer::EAGER) {
7809 RUNTIME_ASSERT(function->IsOptimized());
7810 } else {
7811 RUNTIME_ASSERT(!function->IsOptimized());
7812 }
7813
7814 // Avoid doing too much work when running with --always-opt and keep
7815 // the optimized code around.
7816 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007817 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007818 }
7819
7820 // Count the number of optimized activations of the function.
7821 int activations = 0;
7822 while (!it.done()) {
7823 JavaScriptFrame* frame = it.frame();
7824 if (frame->is_optimized() && frame->function() == *function) {
7825 activations++;
7826 }
7827 it.Advance();
7828 }
7829
7830 // TODO(kasperl): For now, we cannot support removing the optimized
7831 // code when we have recursive invocations of the same function.
7832 if (activations == 0) {
7833 if (FLAG_trace_deopt) {
7834 PrintF("[removing optimized code for: ");
7835 function->PrintName();
7836 PrintF("]\n");
7837 }
7838 function->ReplaceCode(function->shared()->code());
7839 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007840 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007841}
7842
7843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007844RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007845 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007846 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007847 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007848}
7849
7850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007851RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007852 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007853 ASSERT(args.length() == 1);
7854 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007855 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007856
7857 Deoptimizer::DeoptimizeFunction(*function);
7858
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007859 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007860}
7861
7862
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007863RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
7864#if defined(USE_SIMULATOR)
7865 return isolate->heap()->true_value();
7866#else
7867 return isolate->heap()->false_value();
7868#endif
7869}
7870
7871
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007872RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7873 HandleScope scope(isolate);
7874 ASSERT(args.length() == 1);
7875 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7876 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7877 function->MarkForLazyRecompilation();
7878 return isolate->heap()->undefined_value();
7879}
7880
7881
lrn@chromium.org1c092762011-05-09 09:42:16 +00007882RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7883 HandleScope scope(isolate);
7884 ASSERT(args.length() == 1);
7885 if (!V8::UseCrankshaft()) {
7886 return Smi::FromInt(4); // 4 == "never".
7887 }
7888 if (FLAG_always_opt) {
7889 return Smi::FromInt(3); // 3 == "always".
7890 }
7891 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7892 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7893 : Smi::FromInt(2); // 2 == "no".
7894}
7895
7896
7897RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7898 HandleScope scope(isolate);
7899 ASSERT(args.length() == 1);
7900 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7901 return Smi::FromInt(function->shared()->opt_count());
7902}
7903
7904
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007905RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007906 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007907 ASSERT(args.length() == 1);
7908 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7909
7910 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007911 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007912
7913 // We have hit a back edge in an unoptimized frame for a function that was
7914 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007915 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007916 // Keep track of whether we've succeeded in optimizing.
7917 bool succeeded = unoptimized->optimizable();
7918 if (succeeded) {
7919 // If we are trying to do OSR when there are already optimized
7920 // activations of the function, it means (a) the function is directly or
7921 // indirectly recursive and (b) an optimized invocation has been
7922 // deoptimized so that we are currently in an unoptimized activation.
7923 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007924 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007925 while (succeeded && !it.done()) {
7926 JavaScriptFrame* frame = it.frame();
7927 succeeded = !frame->is_optimized() || frame->function() != *function;
7928 it.Advance();
7929 }
7930 }
7931
7932 int ast_id = AstNode::kNoNumber;
7933 if (succeeded) {
7934 // The top JS function is this one, the PC is somewhere in the
7935 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007936 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007937 JavaScriptFrame* frame = it.frame();
7938 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007939 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007940 ASSERT(unoptimized->contains(frame->pc()));
7941
7942 // Use linear search of the unoptimized code's stack check table to find
7943 // the AST id matching the PC.
7944 Address start = unoptimized->instruction_start();
7945 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007946 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007947 uint32_t table_length = Memory::uint32_at(table_cursor);
7948 table_cursor += kIntSize;
7949 for (unsigned i = 0; i < table_length; ++i) {
7950 // Table entries are (AST id, pc offset) pairs.
7951 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7952 if (pc_offset == target_pc_offset) {
7953 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7954 break;
7955 }
7956 table_cursor += 2 * kIntSize;
7957 }
7958 ASSERT(ast_id != AstNode::kNoNumber);
7959 if (FLAG_trace_osr) {
7960 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7961 function->PrintName();
7962 PrintF("]\n");
7963 }
7964
7965 // Try to compile the optimized code. A true return value from
7966 // CompileOptimized means that compilation succeeded, not necessarily
7967 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007968 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7969 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007970 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7971 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007972 if (data->OsrPcOffset()->value() >= 0) {
7973 if (FLAG_trace_osr) {
7974 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007975 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007976 }
7977 ASSERT(data->OsrAstId()->value() == ast_id);
7978 } else {
7979 // We may never generate the desired OSR entry if we emit an
7980 // early deoptimize.
7981 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007982 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007983 } else {
7984 succeeded = false;
7985 }
7986 }
7987
7988 // Revert to the original stack checks in the original unoptimized code.
7989 if (FLAG_trace_osr) {
7990 PrintF("[restoring original stack checks in ");
7991 function->PrintName();
7992 PrintF("]\n");
7993 }
7994 StackCheckStub check_stub;
7995 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007996 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007997 Deoptimizer::RevertStackCheckCode(*unoptimized,
7998 *check_code,
7999 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008000
8001 // Allow OSR only at nesting level zero again.
8002 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8003
8004 // If the optimization attempt succeeded, return the AST id tagged as a
8005 // smi. This tells the builtin that we need to translate the unoptimized
8006 // frame to an optimized one.
8007 if (succeeded) {
8008 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8009 return Smi::FromInt(ast_id);
8010 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008011 if (function->IsMarkedForLazyRecompilation()) {
8012 function->ReplaceCode(function->shared()->code());
8013 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008014 return Smi::FromInt(-1);
8015 }
8016}
8017
8018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008019RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008020 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008021 ASSERT(args.length() == 1);
8022 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8023 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8024}
8025
8026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008027RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008028 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008029 ASSERT(args.length() == 1);
8030 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8031 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8032}
8033
8034
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008035RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008036 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008037 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008038
kasper.lund7276f142008-07-30 08:49:36 +00008039 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008040 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008041 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008042 { MaybeObject* maybe_result =
8043 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008044 if (!maybe_result->ToObject(&result)) return maybe_result;
8045 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008046
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008047 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008048
kasper.lund7276f142008-07-30 08:49:36 +00008049 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008050}
8051
lrn@chromium.org303ada72010-10-27 09:33:13 +00008052
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008053RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8054 NoHandleAllocation ha;
8055 ASSERT(args.length() == 1);
8056 JSObject* extension_object;
8057 if (args[0]->IsJSObject()) {
8058 extension_object = JSObject::cast(args[0]);
8059 } else {
8060 // Convert the object to a proper JavaScript object.
8061 MaybeObject* maybe_js_object = args[0]->ToObject();
8062 if (!maybe_js_object->To(&extension_object)) {
8063 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8064 HandleScope scope(isolate);
8065 Handle<Object> handle = args.at<Object>(0);
8066 Handle<Object> result =
8067 isolate->factory()->NewTypeError("with_expression",
8068 HandleVector(&handle, 1));
8069 return isolate->Throw(*result);
8070 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008071 return maybe_js_object;
8072 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008073 }
8074 }
8075
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008076 Context* context;
8077 MaybeObject* maybe_context =
8078 isolate->heap()->AllocateWithContext(isolate->context(),
8079 extension_object);
8080 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008081 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008082 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008083}
8084
8085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008086RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008087 NoHandleAllocation ha;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008088 ASSERT(args.length() == 2);
8089 String* name = String::cast(args[0]);
8090 Object* thrown_object = args[1];
8091 Context* context;
8092 MaybeObject* maybe_context =
8093 isolate->heap()->AllocateCatchContext(isolate->context(),
8094 name,
8095 thrown_object);
8096 if (!maybe_context->To(&context)) return maybe_context;
8097 isolate->set_context(context);
8098 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008099}
8100
8101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008102RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008103 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008104 ASSERT(args.length() == 2);
8105
8106 CONVERT_ARG_CHECKED(Context, context, 0);
8107 CONVERT_ARG_CHECKED(String, name, 1);
8108
8109 int index;
8110 PropertyAttributes attributes;
8111 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008112 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008113
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008114 // If the slot was not found the result is true.
8115 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008116 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008117 }
8118
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008119 // If the slot was found in a context, it should be DONT_DELETE.
8120 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008121 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008122 }
8123
8124 // The slot was found in a JSObject, either a context extension object,
8125 // the global object, or an arguments object. Try to delete it
8126 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8127 // which allows deleting all parameters in functions that mention
8128 // 'arguments', we do this even for the case of slots found on an
8129 // arguments object. The slot was found on an arguments object if the
8130 // index is non-negative.
8131 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8132 if (index >= 0) {
8133 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
8134 } else {
8135 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
8136 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008137}
8138
8139
ager@chromium.orga1645e22009-09-09 19:27:10 +00008140// A mechanism to return a pair of Object pointers in registers (if possible).
8141// How this is achieved is calling convention-dependent.
8142// All currently supported x86 compiles uses calling conventions that are cdecl
8143// variants where a 64-bit value is returned in two 32-bit registers
8144// (edx:eax on ia32, r1:r0 on ARM).
8145// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8146// In Win64 calling convention, a struct of two pointers is returned in memory,
8147// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008148#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008149struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008150 MaybeObject* x;
8151 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008152};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008153
lrn@chromium.org303ada72010-10-27 09:33:13 +00008154static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008155 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008156 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8157 // In Win64 they are assigned to a hidden first argument.
8158 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008159}
8160#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008161typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008162static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008163 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008164 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008165}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008166#endif
8167
8168
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008169static inline MaybeObject* Unhole(Heap* heap,
8170 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008171 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008172 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8173 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008174 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008175}
8176
8177
danno@chromium.org40cb8782011-05-25 07:58:50 +00008178static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8179 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008180 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008181 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008182 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008183 JSFunction* context_extension_function =
8184 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008185 // If the holder isn't a context extension object, we just return it
8186 // as the receiver. This allows arguments objects to be used as
8187 // receivers, but only if they are put in the context scope chain
8188 // explicitly via a with-statement.
8189 Object* constructor = holder->map()->constructor();
8190 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008191 // Fall back to using the global object as the implicit receiver if
8192 // the property turns out to be a local variable allocated in a
8193 // context extension object - introduced via eval. Implicit global
8194 // receivers are indicated with the hole value.
8195 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008196}
8197
8198
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008199static ObjectPair LoadContextSlotHelper(Arguments args,
8200 Isolate* isolate,
8201 bool throw_error) {
8202 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008203 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008204
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008205 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008206 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008207 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008208 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008209 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008210
8211 int index;
8212 PropertyAttributes attributes;
8213 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008214 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008215
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008216 // If the index is non-negative, the slot has been found in a local
8217 // variable or a parameter. Read it from the context object or the
8218 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008219 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008220 // If the "property" we were looking for is a local variable or an
8221 // argument in a context, the receiver is the global object; see
8222 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008223 //
8224 // Use the hole as the receiver to signal that the receiver is
8225 // implicit and that the global receiver should be used.
8226 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008227 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008228 ? Context::cast(*holder)->get(index)
8229 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008230 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008231 }
8232
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008233 // If the holder is found, we read the property from it.
8234 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008235 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008236 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008237 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008238 if (object->IsGlobalObject()) {
8239 receiver = GlobalObject::cast(object)->global_receiver();
8240 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008241 // Use the hole as the receiver to signal that the receiver is
8242 // implicit and that the global receiver should be used.
8243 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008244 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008245 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008246 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008247
8248 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008249 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008250
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008251 // No need to unhole the value here. This is taken care of by the
8252 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008253 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008254 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008255 }
8256
8257 if (throw_error) {
8258 // The property doesn't exist - throw exception.
8259 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008260 isolate->factory()->NewReferenceError("not_defined",
8261 HandleVector(&name, 1));
8262 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008263 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008264 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008265 return MakePair(isolate->heap()->undefined_value(),
8266 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008267 }
8268}
8269
8270
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008271RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008272 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008273}
8274
8275
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008276RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008277 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008278}
8279
8280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008281RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008282 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008283 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008284
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008285 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008286 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008287 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008288 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008289 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8290 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008291 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008292
8293 int index;
8294 PropertyAttributes attributes;
8295 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008296 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008297
8298 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008299 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008300 // Ignore if read_only variable.
8301 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008302 // Context is a fixed array and set cannot fail.
8303 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008304 } else if (strict_mode == kStrictMode) {
8305 // Setting read only property in strict mode.
8306 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008307 isolate->factory()->NewTypeError("strict_cannot_assign",
8308 HandleVector(&name, 1));
8309 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008310 }
8311 } else {
8312 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008313 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008314 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008315 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008316 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008317 return Failure::Exception();
8318 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008319 }
8320 return *value;
8321 }
8322
8323 // Slow case: The property is not in a FixedArray context.
8324 // It is either in an JSObject extension context or it was not found.
8325 Handle<JSObject> context_ext;
8326
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008327 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008328 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008329 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008330 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008331 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008332 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008333
8334 if (strict_mode == kStrictMode) {
8335 // Throw in strict mode (assignment to undefined variable).
8336 Handle<Object> error =
8337 isolate->factory()->NewReferenceError(
8338 "not_defined", HandleVector(&name, 1));
8339 return isolate->Throw(*error);
8340 }
8341 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008342 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008343 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008344 }
8345
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008346 // Set the property, but ignore if read_only variable on the context
8347 // extension object itself.
8348 if ((attributes & READ_ONLY) == 0 ||
8349 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008350 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008351 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008352 SetProperty(context_ext, name, value, NONE, strict_mode));
8353 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008354 // Setting read only property in strict mode.
8355 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008356 isolate->factory()->NewTypeError(
8357 "strict_cannot_assign", HandleVector(&name, 1));
8358 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008359 }
8360 return *value;
8361}
8362
8363
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008364RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008365 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008366 ASSERT(args.length() == 1);
8367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008368 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008369}
8370
8371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008372RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008373 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008374 ASSERT(args.length() == 1);
8375
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008376 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008377}
8378
8379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008380RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008381 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008382 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008383}
8384
8385
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008386RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008387 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008388 ASSERT(args.length() == 1);
8389
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008390 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008391 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008392 isolate->factory()->NewReferenceError("not_defined",
8393 HandleVector(&name, 1));
8394 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008395}
8396
8397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008398RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008399 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008400
8401 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008402 if (isolate->stack_guard()->IsStackOverflow()) {
8403 NoHandleAllocation na;
8404 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008405 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008406
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008407 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008408}
8409
8410
8411// NOTE: These PrintXXX functions are defined for all builds (not just
8412// DEBUG builds) because we may want to be able to trace function
8413// calls in all modes.
8414static void PrintString(String* str) {
8415 // not uncommon to have empty strings
8416 if (str->length() > 0) {
8417 SmartPointer<char> s =
8418 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8419 PrintF("%s", *s);
8420 }
8421}
8422
8423
8424static void PrintObject(Object* obj) {
8425 if (obj->IsSmi()) {
8426 PrintF("%d", Smi::cast(obj)->value());
8427 } else if (obj->IsString() || obj->IsSymbol()) {
8428 PrintString(String::cast(obj));
8429 } else if (obj->IsNumber()) {
8430 PrintF("%g", obj->Number());
8431 } else if (obj->IsFailure()) {
8432 PrintF("<failure>");
8433 } else if (obj->IsUndefined()) {
8434 PrintF("<undefined>");
8435 } else if (obj->IsNull()) {
8436 PrintF("<null>");
8437 } else if (obj->IsTrue()) {
8438 PrintF("<true>");
8439 } else if (obj->IsFalse()) {
8440 PrintF("<false>");
8441 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008442 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008443 }
8444}
8445
8446
8447static int StackSize() {
8448 int n = 0;
8449 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8450 return n;
8451}
8452
8453
8454static void PrintTransition(Object* result) {
8455 // indentation
8456 { const int nmax = 80;
8457 int n = StackSize();
8458 if (n <= nmax)
8459 PrintF("%4d:%*s", n, n, "");
8460 else
8461 PrintF("%4d:%*s", n, nmax, "...");
8462 }
8463
8464 if (result == NULL) {
8465 // constructor calls
8466 JavaScriptFrameIterator it;
8467 JavaScriptFrame* frame = it.frame();
8468 if (frame->IsConstructor()) PrintF("new ");
8469 // function name
8470 Object* fun = frame->function();
8471 if (fun->IsJSFunction()) {
8472 PrintObject(JSFunction::cast(fun)->shared()->name());
8473 } else {
8474 PrintObject(fun);
8475 }
8476 // function arguments
8477 // (we are intentionally only printing the actually
8478 // supplied parameters, not all parameters required)
8479 PrintF("(this=");
8480 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008481 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008482 for (int i = 0; i < length; i++) {
8483 PrintF(", ");
8484 PrintObject(frame->GetParameter(i));
8485 }
8486 PrintF(") {\n");
8487
8488 } else {
8489 // function result
8490 PrintF("} -> ");
8491 PrintObject(result);
8492 PrintF("\n");
8493 }
8494}
8495
8496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008497RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008498 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008499 NoHandleAllocation ha;
8500 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008501 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008502}
8503
8504
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008505RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008506 NoHandleAllocation ha;
8507 PrintTransition(args[0]);
8508 return args[0]; // return TOS
8509}
8510
8511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008512RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008513 NoHandleAllocation ha;
8514 ASSERT(args.length() == 1);
8515
8516#ifdef DEBUG
8517 if (args[0]->IsString()) {
8518 // If we have a string, assume it's a code "marker"
8519 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008520 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008521 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008522 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8523 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008524 } else {
8525 PrintF("DebugPrint: ");
8526 }
8527 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008528 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008529 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008530 HeapObject::cast(args[0])->map()->Print();
8531 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008532#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008533 // ShortPrint is available in release mode. Print is not.
8534 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008535#endif
8536 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008537 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008538
8539 return args[0]; // return TOS
8540}
8541
8542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008543RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008544 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008545 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008546 isolate->PrintStack();
8547 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008548}
8549
8550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008551RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008552 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008553 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008554
8555 // According to ECMA-262, section 15.9.1, page 117, the precision of
8556 // the number in a Date object representing a particular instant in
8557 // time is milliseconds. Therefore, we floor the result of getting
8558 // the OS time.
8559 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008560 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008561}
8562
8563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008564RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008565 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008566 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008567
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008568 CONVERT_ARG_CHECKED(String, str, 0);
8569 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008570
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008571 CONVERT_ARG_CHECKED(JSArray, output, 1);
8572 RUNTIME_ASSERT(output->HasFastElements());
8573
8574 AssertNoAllocation no_allocation;
8575
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008576 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008577 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8578 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008579 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008580 result = DateParser::Parse(str->ToAsciiVector(),
8581 output_array,
8582 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008583 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008584 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008585 result = DateParser::Parse(str->ToUC16Vector(),
8586 output_array,
8587 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008588 }
8589
8590 if (result) {
8591 return *output;
8592 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008593 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008594 }
8595}
8596
8597
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008598RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008599 NoHandleAllocation ha;
8600 ASSERT(args.length() == 1);
8601
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008602 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008603 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008604 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008605}
8606
8607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008608RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008609 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008610 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008611
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008612 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008613}
8614
8615
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008616RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008617 NoHandleAllocation ha;
8618 ASSERT(args.length() == 1);
8619
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008620 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008621 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008622}
8623
8624
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008625RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008626 ASSERT(args.length() == 1);
8627 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008628 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008629 return JSGlobalObject::cast(global)->global_receiver();
8630}
8631
8632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008633RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008634 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008635 ASSERT_EQ(1, args.length());
8636 CONVERT_ARG_CHECKED(String, source, 0);
8637
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008638 source = Handle<String>(source->TryFlattenGetString());
8639 // Optimized fast case where we only have ascii characters.
8640 Handle<Object> result;
8641 if (source->IsSeqAsciiString()) {
8642 result = JsonParser<true>::Parse(source);
8643 } else {
8644 result = JsonParser<false>::Parse(source);
8645 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008646 if (result.is_null()) {
8647 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008648 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008649 return Failure::Exception();
8650 }
8651 return *result;
8652}
8653
8654
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008655bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8656 Handle<Context> context) {
8657 if (context->allow_code_gen_from_strings()->IsFalse()) {
8658 // Check with callback if set.
8659 AllowCodeGenerationFromStringsCallback callback =
8660 isolate->allow_code_gen_callback();
8661 if (callback == NULL) {
8662 // No callback set and code generation disallowed.
8663 return false;
8664 } else {
8665 // Callback set. Let it decide if code generation is allowed.
8666 VMState state(isolate, EXTERNAL);
8667 return callback(v8::Utils::ToLocal(context));
8668 }
8669 }
8670 return true;
8671}
8672
8673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008674RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008675 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008676 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008677 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008678
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008679 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008680 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008681
8682 // Check if global context allows code generation from
8683 // strings. Throw an exception if it doesn't.
8684 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8685 return isolate->Throw(*isolate->factory()->NewError(
8686 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8687 }
8688
8689 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008690 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8691 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008692 true,
8693 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008694 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008695 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008696 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8697 context,
8698 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008699 return *fun;
8700}
8701
8702
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008703static ObjectPair CompileGlobalEval(Isolate* isolate,
8704 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008705 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008706 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008707 Handle<Context> context = Handle<Context>(isolate->context());
8708 Handle<Context> global_context = Handle<Context>(context->global_context());
8709
8710 // Check if global context allows code generation from
8711 // strings. Throw an exception if it doesn't.
8712 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8713 isolate->Throw(*isolate->factory()->NewError(
8714 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8715 return MakePair(Failure::Exception(), NULL);
8716 }
8717
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008718 // Deal with a normal eval call with a string argument. Compile it
8719 // and return the compiled function bound in the local context.
8720 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8721 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008722 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008723 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008724 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008725 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008726 Handle<JSFunction> compiled =
8727 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008728 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008729 return MakePair(*compiled, *receiver);
8730}
8731
8732
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008733RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008734 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008735
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008736 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008737 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008738 Handle<Object> receiver; // Will be overwritten.
8739
8740 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008741 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008742#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008743 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008744 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008745 StackFrameLocator locator;
8746 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008747 ASSERT(Context::cast(frame->context()) == *context);
8748#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008749
8750 // Find where the 'eval' symbol is bound. It is unaliased only if
8751 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008752 int index = -1;
8753 PropertyAttributes attributes = ABSENT;
8754 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008755 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8756 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008757 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008758 // Stop search when eval is found or when the global context is
8759 // reached.
8760 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008761 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008762 }
8763
iposva@chromium.org245aa852009-02-10 00:49:54 +00008764 // If eval could not be resolved, it has been deleted and we need to
8765 // throw a reference error.
8766 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008767 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008768 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008769 isolate->factory()->NewReferenceError("not_defined",
8770 HandleVector(&name, 1));
8771 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008772 }
8773
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008774 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008775 // 'eval' is not bound in the global context. Just call the function
8776 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008777 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008778 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008779 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008780 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008781 }
8782
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008783 // 'eval' is bound in the global context, but it may have been overwritten.
8784 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008785 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008786 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008787 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008788 }
8789
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008790 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008791 return CompileGlobalEval(isolate,
8792 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008793 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008794 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008795}
8796
8797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008798RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008799 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008800
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008801 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008802 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008803
8804 // 'eval' is bound in the global context, but it may have been overwritten.
8805 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008806 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008807 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008808 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008809 }
8810
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008811 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008812 return CompileGlobalEval(isolate,
8813 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008814 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008815 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008816}
8817
8818
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008819RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008820 // This utility adjusts the property attributes for newly created Function
8821 // object ("new Function(...)") by changing the map.
8822 // All it does is changing the prototype property to enumerable
8823 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008824 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825 ASSERT(args.length() == 1);
8826 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008827
8828 Handle<Map> map = func->shared()->strict_mode()
8829 ? isolate->strict_mode_function_instance_map()
8830 : isolate->function_instance_map();
8831
8832 ASSERT(func->map()->instance_type() == map->instance_type());
8833 ASSERT(func->map()->instance_size() == map->instance_size());
8834 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008835 return *func;
8836}
8837
8838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008839RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008840 // Allocate a block of memory in NewSpace (filled with a filler).
8841 // Use as fallback for allocation in generated code when NewSpace
8842 // is full.
8843 ASSERT(args.length() == 1);
8844 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8845 int size = size_smi->value();
8846 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8847 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008848 Heap* heap = isolate->heap();
8849 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008850 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008851 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008852 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008853 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008854 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008855 }
8856 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008857 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008858}
8859
8860
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008861// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008862// array. Returns true if the element was pushed on the stack and
8863// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008864RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008865 ASSERT(args.length() == 2);
8866 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008867 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008868 RUNTIME_ASSERT(array->HasFastElements());
8869 int length = Smi::cast(array->length())->value();
8870 FixedArray* elements = FixedArray::cast(array->elements());
8871 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008872 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008873 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008874 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008875 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008876 { MaybeObject* maybe_obj =
8877 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008878 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8879 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008880 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008881}
8882
8883
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008884/**
8885 * A simple visitor visits every element of Array's.
8886 * The backend storage can be a fixed array for fast elements case,
8887 * or a dictionary for sparse array. Since Dictionary is a subtype
8888 * of FixedArray, the class can be used by both fast and slow cases.
8889 * The second parameter of the constructor, fast_elements, specifies
8890 * whether the storage is a FixedArray or Dictionary.
8891 *
8892 * An index limit is used to deal with the situation that a result array
8893 * length overflows 32-bit non-negative integer.
8894 */
8895class ArrayConcatVisitor {
8896 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008897 ArrayConcatVisitor(Isolate* isolate,
8898 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008899 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008900 isolate_(isolate),
8901 storage_(Handle<FixedArray>::cast(
8902 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008903 index_offset_(0u),
8904 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008905
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008906 ~ArrayConcatVisitor() {
8907 clear_storage();
8908 }
8909
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008910 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008911 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008912 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008913
8914 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008915 if (index < static_cast<uint32_t>(storage_->length())) {
8916 storage_->set(index, *elm);
8917 return;
8918 }
8919 // Our initial estimate of length was foiled, possibly by
8920 // getters on the arrays increasing the length of later arrays
8921 // during iteration.
8922 // This shouldn't happen in anything but pathological cases.
8923 SetDictionaryMode(index);
8924 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008925 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008926 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008927 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008928 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008929 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008930 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008931 // Dictionary needed to grow.
8932 clear_storage();
8933 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008934 }
8935}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008936
8937 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008938 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8939 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008940 } else {
8941 index_offset_ += delta;
8942 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008943 }
8944
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008945 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008946 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008947 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008948 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008949 Handle<Map> map;
8950 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008951 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008952 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008953 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008954 }
8955 array->set_map(*map);
8956 array->set_length(*length);
8957 array->set_elements(*storage_);
8958 return array;
8959 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008960
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008961 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008962 // Convert storage to dictionary mode.
8963 void SetDictionaryMode(uint32_t index) {
8964 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008965 Handle<FixedArray> current_storage(*storage_);
8966 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008967 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008968 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8969 for (uint32_t i = 0; i < current_length; i++) {
8970 HandleScope loop_scope;
8971 Handle<Object> element(current_storage->get(i));
8972 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008973 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008974 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008975 if (!new_storage.is_identical_to(slow_storage)) {
8976 slow_storage = loop_scope.CloseAndEscape(new_storage);
8977 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008978 }
8979 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008980 clear_storage();
8981 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008982 fast_elements_ = false;
8983 }
8984
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008985 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008986 isolate_->global_handles()->Destroy(
8987 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008988 }
8989
8990 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008991 storage_ = Handle<FixedArray>::cast(
8992 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008993 }
8994
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008995 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008996 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008997 // Index after last seen index. Always less than or equal to
8998 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008999 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009000 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009001};
9002
9003
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009004static uint32_t EstimateElementCount(Handle<JSArray> array) {
9005 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9006 int element_count = 0;
9007 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009008 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009009 // Fast elements can't have lengths that are not representable by
9010 // a 32-bit signed integer.
9011 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9012 int fast_length = static_cast<int>(length);
9013 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9014 for (int i = 0; i < fast_length; i++) {
9015 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009016 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009017 break;
9018 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009019 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009020 Handle<NumberDictionary> dictionary(
9021 NumberDictionary::cast(array->elements()));
9022 int capacity = dictionary->Capacity();
9023 for (int i = 0; i < capacity; i++) {
9024 Handle<Object> key(dictionary->KeyAt(i));
9025 if (dictionary->IsKey(*key)) {
9026 element_count++;
9027 }
9028 }
9029 break;
9030 }
9031 default:
9032 // External arrays are always dense.
9033 return length;
9034 }
9035 // As an estimate, we assume that the prototype doesn't contain any
9036 // inherited elements.
9037 return element_count;
9038}
9039
9040
9041
9042template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009043static void IterateExternalArrayElements(Isolate* isolate,
9044 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009045 bool elements_are_ints,
9046 bool elements_are_guaranteed_smis,
9047 ArrayConcatVisitor* visitor) {
9048 Handle<ExternalArrayClass> array(
9049 ExternalArrayClass::cast(receiver->elements()));
9050 uint32_t len = static_cast<uint32_t>(array->length());
9051
9052 ASSERT(visitor != NULL);
9053 if (elements_are_ints) {
9054 if (elements_are_guaranteed_smis) {
9055 for (uint32_t j = 0; j < len; j++) {
9056 HandleScope loop_scope;
9057 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
9058 visitor->visit(j, e);
9059 }
9060 } else {
9061 for (uint32_t j = 0; j < len; j++) {
9062 HandleScope loop_scope;
9063 int64_t val = static_cast<int64_t>(array->get(j));
9064 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9065 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9066 visitor->visit(j, e);
9067 } else {
9068 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009069 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009070 visitor->visit(j, e);
9071 }
9072 }
9073 }
9074 } else {
9075 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009076 HandleScope loop_scope(isolate);
9077 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009078 visitor->visit(j, e);
9079 }
9080 }
9081}
9082
9083
9084// Used for sorting indices in a List<uint32_t>.
9085static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9086 uint32_t a = *ap;
9087 uint32_t b = *bp;
9088 return (a == b) ? 0 : (a < b) ? -1 : 1;
9089}
9090
9091
9092static void CollectElementIndices(Handle<JSObject> object,
9093 uint32_t range,
9094 List<uint32_t>* indices) {
9095 JSObject::ElementsKind kind = object->GetElementsKind();
9096 switch (kind) {
9097 case JSObject::FAST_ELEMENTS: {
9098 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9099 uint32_t length = static_cast<uint32_t>(elements->length());
9100 if (range < length) length = range;
9101 for (uint32_t i = 0; i < length; i++) {
9102 if (!elements->get(i)->IsTheHole()) {
9103 indices->Add(i);
9104 }
9105 }
9106 break;
9107 }
9108 case JSObject::DICTIONARY_ELEMENTS: {
9109 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009110 uint32_t capacity = dict->Capacity();
9111 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009112 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009113 Handle<Object> k(dict->KeyAt(j));
9114 if (dict->IsKey(*k)) {
9115 ASSERT(k->IsNumber());
9116 uint32_t index = static_cast<uint32_t>(k->Number());
9117 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009118 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009119 }
9120 }
9121 }
9122 break;
9123 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009124 default: {
9125 int dense_elements_length;
9126 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009127 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009128 dense_elements_length =
9129 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009130 break;
9131 }
9132 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009133 dense_elements_length =
9134 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009135 break;
9136 }
9137 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009138 dense_elements_length =
9139 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009140 break;
9141 }
9142 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009143 dense_elements_length =
9144 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009145 break;
9146 }
9147 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009148 dense_elements_length =
9149 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009150 break;
9151 }
9152 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009153 dense_elements_length =
9154 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009155 break;
9156 }
9157 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009158 dense_elements_length =
9159 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009160 break;
9161 }
9162 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009163 dense_elements_length =
9164 ExternalFloatArray::cast(object->elements())->length();
9165 break;
9166 }
9167 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9168 dense_elements_length =
9169 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009170 break;
9171 }
9172 default:
9173 UNREACHABLE();
9174 dense_elements_length = 0;
9175 break;
9176 }
9177 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9178 if (range <= length) {
9179 length = range;
9180 // We will add all indices, so we might as well clear it first
9181 // and avoid duplicates.
9182 indices->Clear();
9183 }
9184 for (uint32_t i = 0; i < length; i++) {
9185 indices->Add(i);
9186 }
9187 if (length == range) return; // All indices accounted for already.
9188 break;
9189 }
9190 }
9191
9192 Handle<Object> prototype(object->GetPrototype());
9193 if (prototype->IsJSObject()) {
9194 // The prototype will usually have no inherited element indices,
9195 // but we have to check.
9196 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9197 }
9198}
9199
9200
9201/**
9202 * A helper function that visits elements of a JSArray in numerical
9203 * order.
9204 *
9205 * The visitor argument called for each existing element in the array
9206 * with the element index and the element's value.
9207 * Afterwards it increments the base-index of the visitor by the array
9208 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009209 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009210 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009211static bool IterateElements(Isolate* isolate,
9212 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009213 ArrayConcatVisitor* visitor) {
9214 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9215 switch (receiver->GetElementsKind()) {
9216 case JSObject::FAST_ELEMENTS: {
9217 // Run through the elements FixedArray and use HasElement and GetElement
9218 // to check the prototype for missing elements.
9219 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9220 int fast_length = static_cast<int>(length);
9221 ASSERT(fast_length <= elements->length());
9222 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009223 HandleScope loop_scope(isolate);
9224 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009225 if (!element_value->IsTheHole()) {
9226 visitor->visit(j, element_value);
9227 } else if (receiver->HasElement(j)) {
9228 // Call GetElement on receiver, not its prototype, or getters won't
9229 // have the correct receiver.
9230 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009231 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009232 visitor->visit(j, element_value);
9233 }
9234 }
9235 break;
9236 }
9237 case JSObject::DICTIONARY_ELEMENTS: {
9238 Handle<NumberDictionary> dict(receiver->element_dictionary());
9239 List<uint32_t> indices(dict->Capacity() / 2);
9240 // Collect all indices in the object and the prototypes less
9241 // than length. This might introduce duplicates in the indices list.
9242 CollectElementIndices(receiver, length, &indices);
9243 indices.Sort(&compareUInt32);
9244 int j = 0;
9245 int n = indices.length();
9246 while (j < n) {
9247 HandleScope loop_scope;
9248 uint32_t index = indices[j];
9249 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009250 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009251 visitor->visit(index, element);
9252 // Skip to next different index (i.e., omit duplicates).
9253 do {
9254 j++;
9255 } while (j < n && indices[j] == index);
9256 }
9257 break;
9258 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009259 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9260 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9261 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009262 for (uint32_t j = 0; j < length; j++) {
9263 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9264 visitor->visit(j, e);
9265 }
9266 break;
9267 }
9268 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9269 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009270 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009271 break;
9272 }
9273 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9274 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009275 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009276 break;
9277 }
9278 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9279 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009280 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009281 break;
9282 }
9283 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9284 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009285 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009286 break;
9287 }
9288 case JSObject::EXTERNAL_INT_ELEMENTS: {
9289 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009290 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009291 break;
9292 }
9293 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9294 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009295 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009296 break;
9297 }
9298 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9299 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009300 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009301 break;
9302 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009303 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9304 IterateExternalArrayElements<ExternalDoubleArray, double>(
9305 isolate, receiver, false, false, visitor);
9306 break;
9307 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009308 default:
9309 UNREACHABLE();
9310 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009311 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009312 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009313 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009314}
9315
9316
9317/**
9318 * Array::concat implementation.
9319 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009320 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009321 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009322 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009323RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009324 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009325 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009326
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009327 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9328 int argument_count = static_cast<int>(arguments->length()->Number());
9329 RUNTIME_ASSERT(arguments->HasFastElements());
9330 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009331
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009332 // Pass 1: estimate the length and number of elements of the result.
9333 // The actual length can be larger if any of the arguments have getters
9334 // that mutate other arguments (but will otherwise be precise).
9335 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009336
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009337 uint32_t estimate_result_length = 0;
9338 uint32_t estimate_nof_elements = 0;
9339 {
9340 for (int i = 0; i < argument_count; i++) {
9341 HandleScope loop_scope;
9342 Handle<Object> obj(elements->get(i));
9343 uint32_t length_estimate;
9344 uint32_t element_estimate;
9345 if (obj->IsJSArray()) {
9346 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9347 length_estimate =
9348 static_cast<uint32_t>(array->length()->Number());
9349 element_estimate =
9350 EstimateElementCount(array);
9351 } else {
9352 length_estimate = 1;
9353 element_estimate = 1;
9354 }
9355 // Avoid overflows by capping at kMaxElementCount.
9356 if (JSObject::kMaxElementCount - estimate_result_length <
9357 length_estimate) {
9358 estimate_result_length = JSObject::kMaxElementCount;
9359 } else {
9360 estimate_result_length += length_estimate;
9361 }
9362 if (JSObject::kMaxElementCount - estimate_nof_elements <
9363 element_estimate) {
9364 estimate_nof_elements = JSObject::kMaxElementCount;
9365 } else {
9366 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009367 }
9368 }
9369 }
9370
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009371 // If estimated number of elements is more than half of length, a
9372 // fixed array (fast case) is more time and space-efficient than a
9373 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009374 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009375
9376 Handle<FixedArray> storage;
9377 if (fast_case) {
9378 // The backing storage array must have non-existing elements to
9379 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009380 storage = isolate->factory()->NewFixedArrayWithHoles(
9381 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009382 } else {
9383 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9384 uint32_t at_least_space_for = estimate_nof_elements +
9385 (estimate_nof_elements >> 2);
9386 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009387 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009388 }
9389
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009390 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009391
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009392 for (int i = 0; i < argument_count; i++) {
9393 Handle<Object> obj(elements->get(i));
9394 if (obj->IsJSArray()) {
9395 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009396 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009397 return Failure::Exception();
9398 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009399 } else {
9400 visitor.visit(0, obj);
9401 visitor.increase_index_offset(1);
9402 }
9403 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009404
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009405 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009406}
9407
9408
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009409// This will not allocate (flatten the string), but it may run
9410// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009411RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009412 NoHandleAllocation ha;
9413 ASSERT(args.length() == 1);
9414
9415 CONVERT_CHECKED(String, string, args[0]);
9416 StringInputBuffer buffer(string);
9417 while (buffer.has_more()) {
9418 uint16_t character = buffer.GetNext();
9419 PrintF("%c", character);
9420 }
9421 return string;
9422}
9423
ager@chromium.org5ec48922009-05-05 07:25:34 +00009424// Moves all own elements of an object, that are below a limit, to positions
9425// starting at zero. All undefined values are placed after non-undefined values,
9426// and are followed by non-existing element. Does not change the length
9427// property.
9428// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009429RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009430 ASSERT(args.length() == 2);
9431 CONVERT_CHECKED(JSObject, object, args[0]);
9432 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9433 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009434}
9435
9436
9437// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009438RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009439 ASSERT(args.length() == 2);
9440 CONVERT_CHECKED(JSArray, from, args[0]);
9441 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009442 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009443 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009444 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9445 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009446 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009447 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009448 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009449 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009450 Object* new_map;
9451 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009452 to->set_map(Map::cast(new_map));
9453 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009454 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009455 Object* obj;
9456 { MaybeObject* maybe_obj = from->ResetElements();
9457 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9458 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009459 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009460 return to;
9461}
9462
9463
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009464// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009465RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009466 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009467 CONVERT_CHECKED(JSObject, object, args[0]);
9468 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009469 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009470 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009471 } else if (object->IsJSArray()) {
9472 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009473 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009474 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009475 }
9476}
9477
9478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009479RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009480 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009481
9482 ASSERT_EQ(3, args.length());
9483
ager@chromium.orgac091b72010-05-05 07:34:42 +00009484 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009485 Handle<Object> key1 = args.at<Object>(1);
9486 Handle<Object> key2 = args.at<Object>(2);
9487
9488 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009489 if (!key1->ToArrayIndex(&index1)
9490 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009491 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009492 }
9493
ager@chromium.orgac091b72010-05-05 07:34:42 +00009494 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9495 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009496 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009497 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009498 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009500 RETURN_IF_EMPTY_HANDLE(isolate,
9501 SetElement(jsobject, index1, tmp2, kStrictMode));
9502 RETURN_IF_EMPTY_HANDLE(isolate,
9503 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009504
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009505 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009506}
9507
9508
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009509// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009510// might have elements. Can either return keys (positive integers) or
9511// intervals (pair of a negative integer (-start-1) followed by a
9512// positive (length)) or undefined values.
9513// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009514RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009515 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009516 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009517 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009518 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009519 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009520 // Create an array and get all the keys into it, then remove all the
9521 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009522 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009523 int keys_length = keys->length();
9524 for (int i = 0; i < keys_length; i++) {
9525 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009526 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009527 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009528 // Zap invalid keys.
9529 keys->set_undefined(i);
9530 }
9531 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009532 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009533 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009534 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009535 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009536 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009537 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009538 uint32_t actual_length =
9539 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009540 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009541 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009543 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009544 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009545 }
9546}
9547
9548
9549// DefineAccessor takes an optional final argument which is the
9550// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9551// to the way accessors are implemented, it is set for both the getter
9552// and setter on the first call to DefineAccessor and ignored on
9553// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009554RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009555 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9556 // Compute attributes.
9557 PropertyAttributes attributes = NONE;
9558 if (args.length() == 5) {
9559 CONVERT_CHECKED(Smi, attrs, args[4]);
9560 int value = attrs->value();
9561 // Only attribute bits should be set.
9562 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9563 attributes = static_cast<PropertyAttributes>(value);
9564 }
9565
9566 CONVERT_CHECKED(JSObject, obj, args[0]);
9567 CONVERT_CHECKED(String, name, args[1]);
9568 CONVERT_CHECKED(Smi, flag, args[2]);
9569 CONVERT_CHECKED(JSFunction, fun, args[3]);
9570 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9571}
9572
9573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009574RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009575 ASSERT(args.length() == 3);
9576 CONVERT_CHECKED(JSObject, obj, args[0]);
9577 CONVERT_CHECKED(String, name, args[1]);
9578 CONVERT_CHECKED(Smi, flag, args[2]);
9579 return obj->LookupAccessor(name, flag->value() == 0);
9580}
9581
9582
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009583#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009584RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009585 ASSERT(args.length() == 0);
9586 return Execution::DebugBreakHelper();
9587}
9588
9589
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009590// Helper functions for wrapping and unwrapping stack frame ids.
9591static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009592 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009593 return Smi::FromInt(id >> 2);
9594}
9595
9596
9597static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9598 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9599}
9600
9601
9602// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009603// args[0]: debug event listener function to set or null or undefined for
9604// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009605// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009606RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009607 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009608 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9609 args[0]->IsUndefined() ||
9610 args[0]->IsNull());
9611 Handle<Object> callback = args.at<Object>(0);
9612 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009613 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009614
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009615 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009616}
9617
9618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009619RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009620 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009621 isolate->stack_guard()->DebugBreak();
9622 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009623}
9624
9625
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009626static MaybeObject* DebugLookupResultValue(Heap* heap,
9627 Object* receiver,
9628 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009629 LookupResult* result,
9630 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009631 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009632 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009633 case NORMAL:
9634 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009635 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009636 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009637 }
9638 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009639 case FIELD:
9640 value =
9641 JSObject::cast(
9642 result->holder())->FastPropertyAt(result->GetFieldIndex());
9643 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009644 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009645 }
9646 return value;
9647 case CONSTANT_FUNCTION:
9648 return result->GetConstantFunction();
9649 case CALLBACKS: {
9650 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009651 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009652 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009653 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009654 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009655 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009656 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009657 maybe_value = heap->isolate()->pending_exception();
9658 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009659 if (caught_exception != NULL) {
9660 *caught_exception = true;
9661 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009662 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009663 }
9664 return value;
9665 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009666 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009667 }
9668 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009669 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009670 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009671 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009672 case CONSTANT_TRANSITION:
9673 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009674 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009675 default:
9676 UNREACHABLE();
9677 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009678 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009679 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009680}
9681
9682
ager@chromium.org32912102009-01-16 10:38:43 +00009683// Get debugger related details for an object property.
9684// args[0]: object holding property
9685// args[1]: name of the property
9686//
9687// The array returned contains the following information:
9688// 0: Property value
9689// 1: Property details
9690// 2: Property value is exception
9691// 3: Getter function if defined
9692// 4: Setter function if defined
9693// Items 2-4 are only filled if the property has either a getter or a setter
9694// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009695RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009696 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009697
9698 ASSERT(args.length() == 2);
9699
9700 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9701 CONVERT_ARG_CHECKED(String, name, 1);
9702
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009703 // Make sure to set the current context to the context before the debugger was
9704 // entered (if the debugger is entered). The reason for switching context here
9705 // is that for some property lookups (accessors and interceptors) callbacks
9706 // into the embedding application can occour, and the embedding application
9707 // could have the assumption that its own global context is the current
9708 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009709 SaveContext save(isolate);
9710 if (isolate->debug()->InDebugger()) {
9711 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009712 }
9713
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009714 // Skip the global proxy as it has no properties and always delegates to the
9715 // real global object.
9716 if (obj->IsJSGlobalProxy()) {
9717 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9718 }
9719
9720
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009721 // Check if the name is trivially convertible to an index and get the element
9722 // if so.
9723 uint32_t index;
9724 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009725 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009726 Object* element_or_char;
9727 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009728 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009729 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9730 return maybe_element_or_char;
9731 }
9732 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009733 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009734 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009735 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009736 }
9737
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009738 // Find the number of objects making up this.
9739 int length = LocalPrototypeChainLength(*obj);
9740
9741 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009742 Handle<JSObject> jsproto = obj;
9743 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009744 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009745 jsproto->LocalLookup(*name, &result);
9746 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009747 // LookupResult is not GC safe as it holds raw object pointers.
9748 // GC can happen later in this code so put the required fields into
9749 // local variables using handles when required for later use.
9750 PropertyType result_type = result.type();
9751 Handle<Object> result_callback_obj;
9752 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009753 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9754 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009755 }
9756 Smi* property_details = result.GetPropertyDetails().AsSmi();
9757 // DebugLookupResultValue can cause GC so details from LookupResult needs
9758 // to be copied to handles before this.
9759 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009760 Object* raw_value;
9761 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009762 DebugLookupResultValue(isolate->heap(), *obj, *name,
9763 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009764 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9765 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009766 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009767
9768 // If the callback object is a fixed array then it contains JavaScript
9769 // getter and/or setter.
9770 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9771 result_callback_obj->IsFixedArray();
9772 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009773 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009774 details->set(0, *value);
9775 details->set(1, property_details);
9776 if (hasJavaScriptAccessors) {
9777 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009778 caught_exception ? isolate->heap()->true_value()
9779 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009780 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9781 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9782 }
9783
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009784 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009785 }
9786 if (i < length - 1) {
9787 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9788 }
9789 }
9790
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009791 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009792}
9793
9794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009795RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009796 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009797
9798 ASSERT(args.length() == 2);
9799
9800 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9801 CONVERT_ARG_CHECKED(String, name, 1);
9802
9803 LookupResult result;
9804 obj->Lookup(*name, &result);
9805 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009806 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009807 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009808 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009809}
9810
9811
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009812// Return the property type calculated from the property details.
9813// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009814RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009815 ASSERT(args.length() == 1);
9816 CONVERT_CHECKED(Smi, details, args[0]);
9817 PropertyType type = PropertyDetails(details).type();
9818 return Smi::FromInt(static_cast<int>(type));
9819}
9820
9821
9822// Return the property attribute calculated from the property details.
9823// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009824RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009825 ASSERT(args.length() == 1);
9826 CONVERT_CHECKED(Smi, details, args[0]);
9827 PropertyAttributes attributes = PropertyDetails(details).attributes();
9828 return Smi::FromInt(static_cast<int>(attributes));
9829}
9830
9831
9832// Return the property insertion index calculated from the property details.
9833// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009834RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009835 ASSERT(args.length() == 1);
9836 CONVERT_CHECKED(Smi, details, args[0]);
9837 int index = PropertyDetails(details).index();
9838 return Smi::FromInt(index);
9839}
9840
9841
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009842// Return property value from named interceptor.
9843// args[0]: object
9844// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009845RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009846 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009847 ASSERT(args.length() == 2);
9848 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9849 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9850 CONVERT_ARG_CHECKED(String, name, 1);
9851
9852 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009853 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009854}
9855
9856
9857// Return element value from indexed interceptor.
9858// args[0]: object
9859// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009860RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009861 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009862 ASSERT(args.length() == 2);
9863 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9864 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9865 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9866
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009867 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009868}
9869
9870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009871RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009872 ASSERT(args.length() >= 1);
9873 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009874 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009875 if (isolate->debug()->break_id() == 0 ||
9876 break_id != isolate->debug()->break_id()) {
9877 return isolate->Throw(
9878 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009879 }
9880
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009881 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009882}
9883
9884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009885RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009886 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009887 ASSERT(args.length() == 1);
9888
9889 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009890 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009891 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9892 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009893 if (!maybe_result->ToObject(&result)) return maybe_result;
9894 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009895
9896 // Count all frames which are relevant to debugging stack trace.
9897 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009898 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009899 if (id == StackFrame::NO_ID) {
9900 // If there is no JavaScript stack frame count is 0.
9901 return Smi::FromInt(0);
9902 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009903 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009904 return Smi::FromInt(n);
9905}
9906
9907
9908static const int kFrameDetailsFrameIdIndex = 0;
9909static const int kFrameDetailsReceiverIndex = 1;
9910static const int kFrameDetailsFunctionIndex = 2;
9911static const int kFrameDetailsArgumentCountIndex = 3;
9912static const int kFrameDetailsLocalCountIndex = 4;
9913static const int kFrameDetailsSourcePositionIndex = 5;
9914static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009915static const int kFrameDetailsAtReturnIndex = 7;
9916static const int kFrameDetailsDebuggerFrameIndex = 8;
9917static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009918
9919// Return an array with frame details
9920// args[0]: number: break id
9921// args[1]: number: frame index
9922//
9923// The array returned contains the following information:
9924// 0: Frame id
9925// 1: Receiver
9926// 2: Function
9927// 3: Argument count
9928// 4: Local count
9929// 5: Source position
9930// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009931// 7: Is at return
9932// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009933// Arguments name, value
9934// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009935// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009936RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009937 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009938 ASSERT(args.length() == 2);
9939
9940 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009941 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009942 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9943 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009944 if (!maybe_check->ToObject(&check)) return maybe_check;
9945 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009946 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009947 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009948
9949 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009950 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009951 if (id == StackFrame::NO_ID) {
9952 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009953 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009954 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009955 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009956 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009957 for (; !it.done(); it.Advance()) {
9958 if (count == index) break;
9959 count++;
9960 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009961 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009962
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009963 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009964 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009965
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009966 // Traverse the saved contexts chain to find the active context for the
9967 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009968 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009969 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009970 save = save->prev();
9971 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009972 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009973
9974 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009975 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009976
9977 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009978 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009979 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009980
9981 // Check for constructor frame.
9982 bool constructor = it.frame()->IsConstructor();
9983
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009984 // Get scope info and read from it for local variable information.
9985 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009986 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009987 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009988
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009989 // Get the nearest enclosing function context.
9990 Handle<Context> context(Context::cast(it.frame()->context())->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009991
9992 // Get the locals names and values into a temporary array.
9993 //
9994 // TODO(1240907): Hide compiler-introduced stack variables
9995 // (e.g. .result)? For users of the debugger, they will probably be
9996 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009997 Handle<FixedArray> locals =
9998 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009999
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010000 // Fill in the names of the locals.
10001 for (int i = 0; i < info.NumberOfLocals(); i++) {
10002 locals->set(i * 2, *info.LocalName(i));
10003 }
10004
10005 // Fill in the values of the locals.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010006 if (is_optimized_frame) {
10007 // If we are inspecting an optimized frame use undefined as the
10008 // value for all locals.
10009 //
10010 // TODO(1140): We should be able to get the correct values
10011 // for locals in optimized frames.
10012 for (int i = 0; i < info.NumberOfLocals(); i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010013 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010014 }
10015 } else {
10016 for (int i = 0; i < info.number_of_stack_slots(); i++) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010017 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010018 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010019 }
10020 for (int i = info.number_of_stack_slots(); i < info.NumberOfLocals(); i++) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010021 Handle<String> name = info.LocalName(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010022 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010023 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010024 }
10025 }
10026
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010027 // Check whether this frame is positioned at return. If not top
10028 // frame or if the frame is optimized it cannot be at a return.
10029 bool at_return = false;
10030 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010031 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010032 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010033
10034 // If positioned just before return find the value to be returned and add it
10035 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010036 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010037 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010038 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010039 Address internal_frame_sp = NULL;
10040 while (!it2.done()) {
10041 if (it2.frame()->is_internal()) {
10042 internal_frame_sp = it2.frame()->sp();
10043 } else {
10044 if (it2.frame()->is_java_script()) {
10045 if (it2.frame()->id() == it.frame()->id()) {
10046 // The internal frame just before the JavaScript frame contains the
10047 // value to return on top. A debug break at return will create an
10048 // internal frame to store the return value (eax/rax/r0) before
10049 // entering the debug break exit frame.
10050 if (internal_frame_sp != NULL) {
10051 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010052 Handle<Object>(Memory::Object_at(internal_frame_sp),
10053 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010054 break;
10055 }
10056 }
10057 }
10058
10059 // Indicate that the previous frame was not an internal frame.
10060 internal_frame_sp = NULL;
10061 }
10062 it2.Advance();
10063 }
10064 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010065
10066 // Now advance to the arguments adapter frame (if any). It contains all
10067 // the provided parameters whereas the function frame always have the number
10068 // of arguments matching the functions parameters. The rest of the
10069 // information (except for what is collected above) is the same.
10070 it.AdvanceToArgumentsFrame();
10071
10072 // Find the number of arguments to fill. At least fill the number of
10073 // parameters for the function and fill more if more parameters are provided.
10074 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010075 if (argument_count < it.frame()->ComputeParametersCount()) {
10076 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010077 }
10078
10079 // Calculate the size of the result.
10080 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010081 2 * (argument_count + info.NumberOfLocals()) +
10082 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010083 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010084
10085 // Add the frame id.
10086 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10087
10088 // Add the function (same as in function frame).
10089 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
10090
10091 // Add the arguments count.
10092 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10093
10094 // Add the locals count
10095 details->set(kFrameDetailsLocalCountIndex,
10096 Smi::FromInt(info.NumberOfLocals()));
10097
10098 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010099 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010100 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10101 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010102 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010103 }
10104
10105 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010106 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010107
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010108 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010109 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010110
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010111 // Add information on whether this frame is invoked in the debugger context.
10112 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010113 heap->ToBoolean(*save->context() ==
10114 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010115
10116 // Fill the dynamic part.
10117 int details_index = kFrameDetailsFirstDynamicIndex;
10118
10119 // Add arguments name and value.
10120 for (int i = 0; i < argument_count; i++) {
10121 // Name of the argument.
10122 if (i < info.number_of_parameters()) {
10123 details->set(details_index++, *info.parameter_name(i));
10124 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010125 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010126 }
10127
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010128 // Parameter value. If we are inspecting an optimized frame, use
10129 // undefined as the value.
10130 //
10131 // TODO(3141533): We should be able to get the actual parameter
10132 // value for optimized frames.
10133 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010134 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010135 details->set(details_index++, it.frame()->GetParameter(i));
10136 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010137 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010138 }
10139 }
10140
10141 // Add locals name and value from the temporary copy from the function frame.
10142 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10143 details->set(details_index++, locals->get(i));
10144 }
10145
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010146 // Add the value being returned.
10147 if (at_return) {
10148 details->set(details_index++, *return_value);
10149 }
10150
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010151 // Add the receiver (same as in function frame).
10152 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10153 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010154 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010155 if (!receiver->IsJSObject()) {
10156 // If the receiver is NOT a JSObject we have hit an optimization
10157 // where a value object is not converted into a wrapped JS objects.
10158 // To hide this optimization from the debugger, we wrap the receiver
10159 // by creating correct wrapper object based on the calling frame's
10160 // global context.
10161 it.Advance();
10162 Handle<Context> calling_frames_global_context(
10163 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010164 receiver =
10165 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010166 }
10167 details->set(kFrameDetailsReceiverIndex, *receiver);
10168
10169 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010170 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010171}
10172
10173
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010174// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010175static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010176 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010177 Handle<SerializedScopeInfo> serialized_scope_info,
10178 ScopeInfo<>& scope_info,
10179 Handle<Context> context,
10180 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010181 // Fill all context locals to the context extension.
10182 for (int i = Context::MIN_CONTEXT_SLOTS;
10183 i < scope_info.number_of_context_slots();
10184 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010185 int context_index = serialized_scope_info->ContextSlotIndex(
10186 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010187
whesse@chromium.org7b260152011-06-20 15:33:18 +000010188 RETURN_IF_EMPTY_HANDLE_VALUE(
10189 isolate,
10190 SetProperty(scope_object,
10191 scope_info.context_slot_name(i),
10192 Handle<Object>(context->get(context_index), isolate),
10193 NONE,
10194 kNonStrictMode),
10195 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010196 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010197
10198 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010199}
10200
10201
10202// Create a plain JSObject which materializes the local scope for the specified
10203// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010204static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
10205 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010206 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010207 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010208 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10209 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010210
10211 // Allocate and initialize a JSObject with all the arguments, stack locals
10212 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010213 Handle<JSObject> local_scope =
10214 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010215
10216 // First fill all parameters.
10217 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010218 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010219 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010220 SetProperty(local_scope,
10221 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010222 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010223 NONE,
10224 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010225 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010226 }
10227
10228 // Second fill all stack locals.
10229 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010230 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010231 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010232 SetProperty(local_scope,
10233 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010234 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010235 NONE,
10236 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010237 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010238 }
10239
10240 // Third fill all context locals.
10241 Handle<Context> frame_context(Context::cast(frame->context()));
10242 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010243 if (!CopyContextLocalsToScopeObject(isolate,
10244 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010245 function_context, local_scope)) {
10246 return Handle<JSObject>();
10247 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010248
10249 // Finally copy any properties from the function context extension. This will
10250 // be variables introduced by eval.
10251 if (function_context->closure() == *function) {
10252 if (function_context->has_extension() &&
10253 !function_context->IsGlobalContext()) {
10254 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010255 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010256 for (int i = 0; i < keys->length(); i++) {
10257 // Names of variables introduced by eval are strings.
10258 ASSERT(keys->get(i)->IsString());
10259 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010260 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010261 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010262 SetProperty(local_scope,
10263 key,
10264 GetProperty(ext, key),
10265 NONE,
10266 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010267 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010268 }
10269 }
10270 }
10271 return local_scope;
10272}
10273
10274
10275// Create a plain JSObject which materializes the closure content for the
10276// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010277static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10278 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010279 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010280
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010281 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010282 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10283 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010284
10285 // Allocate and initialize a JSObject with all the content of theis function
10286 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010287 Handle<JSObject> closure_scope =
10288 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010289
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010290 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010291 if (!CopyContextLocalsToScopeObject(isolate,
10292 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010293 context, closure_scope)) {
10294 return Handle<JSObject>();
10295 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010296
10297 // Finally copy any properties from the function context extension. This will
10298 // be variables introduced by eval.
10299 if (context->has_extension()) {
10300 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010301 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010302 for (int i = 0; i < keys->length(); i++) {
10303 // Names of variables introduced by eval are strings.
10304 ASSERT(keys->get(i)->IsString());
10305 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010306 RETURN_IF_EMPTY_HANDLE_VALUE(
10307 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010308 SetProperty(closure_scope,
10309 key,
10310 GetProperty(ext, key),
10311 NONE,
10312 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010313 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010314 }
10315 }
10316
10317 return closure_scope;
10318}
10319
10320
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010321// Create a plain JSObject which materializes the scope for the specified
10322// catch context.
10323static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10324 Handle<Context> context) {
10325 ASSERT(context->IsCatchContext());
10326 Handle<String> name(String::cast(context->extension()));
10327 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10328 Handle<JSObject> catch_scope =
10329 isolate->factory()->NewJSObject(isolate->object_function());
10330 RETURN_IF_EMPTY_HANDLE_VALUE(
10331 isolate,
10332 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10333 Handle<JSObject>());
10334 return catch_scope;
10335}
10336
10337
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010338// Iterate over the actual scopes visible from a stack frame. All scopes are
10339// backed by an actual context except the local scope, which is inserted
10340// "artifically" in the context chain.
10341class ScopeIterator {
10342 public:
10343 enum ScopeType {
10344 ScopeTypeGlobal = 0,
10345 ScopeTypeLocal,
10346 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010347 ScopeTypeClosure,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010348 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010349 };
10350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010351 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10352 : isolate_(isolate),
10353 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010354 function_(JSFunction::cast(frame->function())),
10355 context_(Context::cast(frame->context())),
10356 local_done_(false),
10357 at_local_(false) {
10358
10359 // Check whether the first scope is actually a local scope.
10360 if (context_->IsGlobalContext()) {
10361 // If there is a stack slot for .result then this local scope has been
10362 // created for evaluating top level code and it is not a real local scope.
10363 // Checking for the existence of .result seems fragile, but the scope info
10364 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010365 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010366 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010367 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010368 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010369 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010370 } else if (context_->closure() != *function_) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010371 // The context_ is a with or catch block from the outer function.
10372 ASSERT(context_->IsWithContext() || context_->IsCatchContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010373 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010374 }
10375 }
10376
10377 // More scopes?
10378 bool Done() { return context_.is_null(); }
10379
10380 // Move to the next scope.
10381 void Next() {
10382 // If at a local scope mark the local scope as passed.
10383 if (at_local_) {
10384 at_local_ = false;
10385 local_done_ = true;
10386
10387 // If the current context is not associated with the local scope the
10388 // current context is the next real scope, so don't move to the next
10389 // context in this case.
10390 if (context_->closure() != *function_) {
10391 return;
10392 }
10393 }
10394
10395 // The global scope is always the last in the chain.
10396 if (context_->IsGlobalContext()) {
10397 context_ = Handle<Context>();
10398 return;
10399 }
10400
10401 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010402 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010403
10404 // If passing the local scope indicate that the current scope is now the
10405 // local scope.
10406 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010407 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010408 at_local_ = true;
10409 }
10410 }
10411
10412 // Return the type of the current scope.
10413 int Type() {
10414 if (at_local_) {
10415 return ScopeTypeLocal;
10416 }
10417 if (context_->IsGlobalContext()) {
10418 ASSERT(context_->global()->IsGlobalObject());
10419 return ScopeTypeGlobal;
10420 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010421 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010422 return ScopeTypeClosure;
10423 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010424 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010425 return ScopeTypeCatch;
10426 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010427 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010428 return ScopeTypeWith;
10429 }
10430
10431 // Return the JavaScript object with the content of the current scope.
10432 Handle<JSObject> ScopeObject() {
10433 switch (Type()) {
10434 case ScopeIterator::ScopeTypeGlobal:
10435 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010436 case ScopeIterator::ScopeTypeLocal:
10437 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010438 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010439 case ScopeIterator::ScopeTypeWith:
10440 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010441 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10442 case ScopeIterator::ScopeTypeCatch:
10443 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010444 case ScopeIterator::ScopeTypeClosure:
10445 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010446 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010447 }
10448 UNREACHABLE();
10449 return Handle<JSObject>();
10450 }
10451
10452 // Return the context for this scope. For the local context there might not
10453 // be an actual context.
10454 Handle<Context> CurrentContext() {
10455 if (at_local_ && context_->closure() != *function_) {
10456 return Handle<Context>();
10457 }
10458 return context_;
10459 }
10460
10461#ifdef DEBUG
10462 // Debug print of the content of the current scope.
10463 void DebugPrint() {
10464 switch (Type()) {
10465 case ScopeIterator::ScopeTypeGlobal:
10466 PrintF("Global:\n");
10467 CurrentContext()->Print();
10468 break;
10469
10470 case ScopeIterator::ScopeTypeLocal: {
10471 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010472 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010473 scope_info.Print();
10474 if (!CurrentContext().is_null()) {
10475 CurrentContext()->Print();
10476 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010477 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010478 if (extension->IsJSContextExtensionObject()) {
10479 extension->Print();
10480 }
10481 }
10482 }
10483 break;
10484 }
10485
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010486 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010487 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010488 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010489 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010490
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010491 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010492 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010493 CurrentContext()->extension()->Print();
10494 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010495 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010496
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010497 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010498 PrintF("Closure:\n");
10499 CurrentContext()->Print();
10500 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010501 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010502 if (extension->IsJSContextExtensionObject()) {
10503 extension->Print();
10504 }
10505 }
10506 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010507
10508 default:
10509 UNREACHABLE();
10510 }
10511 PrintF("\n");
10512 }
10513#endif
10514
10515 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010516 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010517 JavaScriptFrame* frame_;
10518 Handle<JSFunction> function_;
10519 Handle<Context> context_;
10520 bool local_done_;
10521 bool at_local_;
10522
10523 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10524};
10525
10526
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010527RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010528 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010529 ASSERT(args.length() == 2);
10530
10531 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010532 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010533 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10534 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010535 if (!maybe_check->ToObject(&check)) return maybe_check;
10536 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010537 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10538
10539 // Get the frame where the debugging is performed.
10540 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010541 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010542 JavaScriptFrame* frame = it.frame();
10543
10544 // Count the visible scopes.
10545 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010546 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010547 n++;
10548 }
10549
10550 return Smi::FromInt(n);
10551}
10552
10553
10554static const int kScopeDetailsTypeIndex = 0;
10555static const int kScopeDetailsObjectIndex = 1;
10556static const int kScopeDetailsSize = 2;
10557
10558// Return an array with scope details
10559// args[0]: number: break id
10560// args[1]: number: frame index
10561// args[2]: number: scope index
10562//
10563// The array returned contains the following information:
10564// 0: Scope type
10565// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010566RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010567 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010568 ASSERT(args.length() == 3);
10569
10570 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010571 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010572 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10573 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010574 if (!maybe_check->ToObject(&check)) return maybe_check;
10575 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010576 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10577 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10578
10579 // Get the frame where the debugging is performed.
10580 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010581 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010582 JavaScriptFrame* frame = frame_it.frame();
10583
10584 // Find the requested scope.
10585 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010586 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010587 for (; !it.Done() && n < index; it.Next()) {
10588 n++;
10589 }
10590 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010591 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010592 }
10593
10594 // Calculate the size of the result.
10595 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010596 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010597
10598 // Fill in scope details.
10599 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010600 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010601 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010602 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010603
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010604 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010605}
10606
10607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010608RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010609 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010610 ASSERT(args.length() == 0);
10611
10612#ifdef DEBUG
10613 // Print the scopes for the top frame.
10614 StackFrameLocator locator;
10615 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010616 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010617 it.DebugPrint();
10618 }
10619#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010620 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010621}
10622
10623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010624RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010625 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010626 ASSERT(args.length() == 1);
10627
10628 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010629 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010630 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10631 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010632 if (!maybe_result->ToObject(&result)) return maybe_result;
10633 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010634
10635 // Count all archived V8 threads.
10636 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010637 for (ThreadState* thread =
10638 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010639 thread != NULL;
10640 thread = thread->Next()) {
10641 n++;
10642 }
10643
10644 // Total number of threads is current thread and archived threads.
10645 return Smi::FromInt(n + 1);
10646}
10647
10648
10649static const int kThreadDetailsCurrentThreadIndex = 0;
10650static const int kThreadDetailsThreadIdIndex = 1;
10651static const int kThreadDetailsSize = 2;
10652
10653// Return an array with thread details
10654// args[0]: number: break id
10655// args[1]: number: thread index
10656//
10657// The array returned contains the following information:
10658// 0: Is current thread?
10659// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010660RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010661 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010662 ASSERT(args.length() == 2);
10663
10664 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010665 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010666 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10667 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010668 if (!maybe_check->ToObject(&check)) return maybe_check;
10669 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010670 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10671
10672 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010673 Handle<FixedArray> details =
10674 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010675
10676 // Thread index 0 is current thread.
10677 if (index == 0) {
10678 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010679 details->set(kThreadDetailsCurrentThreadIndex,
10680 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010681 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010682 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010683 } else {
10684 // Find the thread with the requested index.
10685 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010686 ThreadState* thread =
10687 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010688 while (index != n && thread != NULL) {
10689 thread = thread->Next();
10690 n++;
10691 }
10692 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010693 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010694 }
10695
10696 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010697 details->set(kThreadDetailsCurrentThreadIndex,
10698 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010699 details->set(kThreadDetailsThreadIdIndex,
10700 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010701 }
10702
10703 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010704 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010705}
10706
10707
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010708// Sets the disable break state
10709// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010710RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010711 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010712 ASSERT(args.length() == 1);
10713 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010714 isolate->debug()->set_disable_break(disable_break);
10715 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010716}
10717
10718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010719RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010720 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010721 ASSERT(args.length() == 1);
10722
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010723 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10724 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010725 // Find the number of break points
10726 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010727 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010728 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010729 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010730 Handle<FixedArray>::cast(break_locations));
10731}
10732
10733
10734// Set a break point in a function
10735// args[0]: function
10736// args[1]: number: break source position (within the function source)
10737// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010738RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010739 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010740 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010741 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10742 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010743 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10744 RUNTIME_ASSERT(source_position >= 0);
10745 Handle<Object> break_point_object_arg = args.at<Object>(2);
10746
10747 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010748 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10749 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010750
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010751 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010752}
10753
10754
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010755Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10756 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010757 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010758 // Iterate the heap looking for SharedFunctionInfo generated from the
10759 // script. The inner most SharedFunctionInfo containing the source position
10760 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010761 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762 // which is found is not compiled it is compiled and the heap is iterated
10763 // again as the compilation might create inner functions from the newly
10764 // compiled function and the actual requested break point might be in one of
10765 // these functions.
10766 bool done = false;
10767 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010768 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010769 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010770 while (!done) {
10771 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010772 for (HeapObject* obj = iterator.next();
10773 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010774 if (obj->IsSharedFunctionInfo()) {
10775 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10776 if (shared->script() == *script) {
10777 // If the SharedFunctionInfo found has the requested script data and
10778 // contains the source position it is a candidate.
10779 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010780 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010781 start_position = shared->start_position();
10782 }
10783 if (start_position <= position &&
10784 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010785 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010786 // candidate this is the new candidate.
10787 if (target.is_null()) {
10788 target_start_position = start_position;
10789 target = shared;
10790 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010791 if (target_start_position == start_position &&
10792 shared->end_position() == target->end_position()) {
10793 // If a top-level function contain only one function
10794 // declartion the source for the top-level and the function is
10795 // the same. In that case prefer the non top-level function.
10796 if (!shared->is_toplevel()) {
10797 target_start_position = start_position;
10798 target = shared;
10799 }
10800 } else if (target_start_position <= start_position &&
10801 shared->end_position() <= target->end_position()) {
10802 // This containment check includes equality as a function inside
10803 // a top-level function can share either start or end position
10804 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010805 target_start_position = start_position;
10806 target = shared;
10807 }
10808 }
10809 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010810 }
10811 }
10812 }
10813
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010814 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010815 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010816 }
10817
10818 // If the candidate found is compiled we are done. NOTE: when lazy
10819 // compilation of inner functions is introduced some additional checking
10820 // needs to be done here to compile inner functions.
10821 done = target->is_compiled();
10822 if (!done) {
10823 // If the candidate is not compiled compile it to reveal any inner
10824 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010825 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010826 }
10827 }
10828
10829 return *target;
10830}
10831
10832
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010833// Changes the state of a break point in a script and returns source position
10834// where break point was set. NOTE: Regarding performance see the NOTE for
10835// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010836// args[0]: script to set break point in
10837// args[1]: number: break source position (within the script source)
10838// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010839RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010840 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010841 ASSERT(args.length() == 3);
10842 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10843 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10844 RUNTIME_ASSERT(source_position >= 0);
10845 Handle<Object> break_point_object_arg = args.at<Object>(2);
10846
10847 // Get the script from the script wrapper.
10848 RUNTIME_ASSERT(wrapper->value()->IsScript());
10849 Handle<Script> script(Script::cast(wrapper->value()));
10850
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010851 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010852 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010853 if (!result->IsUndefined()) {
10854 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10855 // Find position within function. The script position might be before the
10856 // source position of the first function.
10857 int position;
10858 if (shared->start_position() > source_position) {
10859 position = 0;
10860 } else {
10861 position = source_position - shared->start_position();
10862 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010863 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010864 position += shared->start_position();
10865 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010866 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010867 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010868}
10869
10870
10871// Clear a break point
10872// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010873RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010874 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010875 ASSERT(args.length() == 1);
10876 Handle<Object> break_point_object_arg = args.at<Object>(0);
10877
10878 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010879 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010880
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010881 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010882}
10883
10884
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010885// Change the state of break on exceptions.
10886// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10887// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010888RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010889 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010891 RUNTIME_ASSERT(args[0]->IsNumber());
10892 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010893
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010894 // If the number doesn't match an enum value, the ChangeBreakOnException
10895 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010896 ExceptionBreakType type =
10897 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010898 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010899 isolate->debug()->ChangeBreakOnException(type, enable);
10900 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010901}
10902
10903
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010904// Returns the state of break on exceptions
10905// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010906RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010907 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010908 ASSERT(args.length() == 1);
10909 RUNTIME_ASSERT(args[0]->IsNumber());
10910
10911 ExceptionBreakType type =
10912 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010913 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010914 return Smi::FromInt(result);
10915}
10916
10917
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010918// Prepare for stepping
10919// args[0]: break id for checking execution state
10920// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010921// args[2]: number of times to perform the step, for step out it is the number
10922// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010923RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010924 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010925 ASSERT(args.length() == 3);
10926 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010927 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010928 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10929 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010930 if (!maybe_check->ToObject(&check)) return maybe_check;
10931 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010932 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010933 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010934 }
10935
10936 // Get the step action and check validity.
10937 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10938 if (step_action != StepIn &&
10939 step_action != StepNext &&
10940 step_action != StepOut &&
10941 step_action != StepInMin &&
10942 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010943 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010944 }
10945
10946 // Get the number of steps.
10947 int step_count = NumberToInt32(args[2]);
10948 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010949 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950 }
10951
ager@chromium.orga1645e22009-09-09 19:27:10 +000010952 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010953 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010954
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010955 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010956 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10957 step_count);
10958 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959}
10960
10961
10962// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010963RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010964 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010965 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010966 isolate->debug()->ClearStepping();
10967 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968}
10969
10970
10971// Creates a copy of the with context chain. The copy of the context chain is
10972// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010973static Handle<Context> CopyWithContextChain(Isolate* isolate,
10974 Handle<Context> current,
10975 Handle<Context> base) {
10976 // At the end of the chain. Return the base context to link to.
10977 if (current->IsFunctionContext() || current->IsGlobalContext()) {
10978 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010979 }
10980
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010981 // Recursively copy the with and catch contexts.
10982 HandleScope scope(isolate);
10983 Handle<Context> previous(current->previous());
10984 Handle<Context> new_previous = CopyWithContextChain(isolate, previous, base);
10985 Handle<Context> new_current;
10986 if (current->IsCatchContext()) {
10987 Handle<String> name(String::cast(current->extension()));
10988 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
10989 new_current =
10990 isolate->factory()->NewCatchContext(new_previous, name, thrown_object);
10991 } else {
10992 Handle<JSObject> extension(JSObject::cast(current->extension()));
10993 new_current =
10994 isolate->factory()->NewWithContext(new_previous, extension);
10995 }
10996 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010997}
10998
10999
11000// Helper function to find or create the arguments object for
11001// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011002static Handle<Object> GetArgumentsObject(Isolate* isolate,
11003 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011004 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011005 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011006 const ScopeInfo<>* sinfo,
11007 Handle<Context> function_context) {
11008 // Try to find the value of 'arguments' to pass as parameter. If it is not
11009 // found (that is the debugged function does not reference 'arguments' and
11010 // does not support eval) then create an 'arguments' object.
11011 int index;
11012 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011013 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011014 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011015 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011016 }
11017 }
11018
11019 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011020 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11021 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011022 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011023 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011024 }
11025 }
11026
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011027 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011028 Handle<JSObject> arguments =
11029 isolate->factory()->NewArgumentsObject(function, length);
11030 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011031
11032 AssertNoAllocation no_gc;
11033 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011034 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011035 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011036 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011037 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011038 return arguments;
11039}
11040
11041
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011042static const char kSourceStr[] =
11043 "(function(arguments,__source__){return eval(__source__);})";
11044
11045
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011046// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011047// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011048// extension part has all the parameters and locals of the function on the
11049// stack frame. A function which calls eval with the code to evaluate is then
11050// compiled in this context and called in this context. As this context
11051// replaces the context of the function on the stack frame a new (empty)
11052// function is created as well to be used as the closure for the context.
11053// This function and the context acts as replacements for the function on the
11054// stack frame presenting the same view of the values of parameters and
11055// local variables as if the piece of JavaScript was evaluated at the point
11056// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011057RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011058 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011059
11060 // Check the execution state and decode arguments frame and source to be
11061 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011062 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011063 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011064 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11065 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011066 if (!maybe_check_result->ToObject(&check_result)) {
11067 return maybe_check_result;
11068 }
11069 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011070 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11071 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011072 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011073 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011074
11075 // Handle the processing of break.
11076 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011077
11078 // Get the frame where the debugging is performed.
11079 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011080 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011081 JavaScriptFrame* frame = it.frame();
11082 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011083 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011084 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011085
11086 // Traverse the saved contexts chain to find the active context for the
11087 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011088 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011089 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011090 save = save->prev();
11091 }
11092 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011093 SaveContext savex(isolate);
11094 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011095
11096 // Create the (empty) function replacing the function on the stack frame for
11097 // the purpose of evaluating in the context created below. It is important
11098 // that this function does not describe any parameters and local variables
11099 // in the context. If it does then this will cause problems with the lookup
11100 // in Context::Lookup, where context slots for parameters and local variables
11101 // are looked at before the extension object.
11102 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011103 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11104 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011105 go_between->set_context(function->context());
11106#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011107 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011108 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11109 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11110#endif
11111
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011112 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011113 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
11114 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011115
11116 // Allocate a new context for the debug evaluation and set the extension
11117 // object build.
11118 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011119 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11120 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011121 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011122 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011123 Handle<Context> frame_context(Context::cast(frame->context()));
11124 Handle<Context> function_context(frame_context->fcontext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011125 context = CopyWithContextChain(isolate, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011126
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011127 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011128 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
11129 context = isolate->factory()->NewWithContext(context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011130 }
11131
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011132 // Wrap the evaluation statement in a new function compiled in the newly
11133 // created context. The function has one parameter which has to be called
11134 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011135 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011136 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011137
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011138 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011139 isolate->factory()->NewStringFromAscii(
11140 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011141
11142 // Currently, the eval code will be executed in non-strict mode,
11143 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011144 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011145 Compiler::CompileEval(function_source,
11146 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011147 context->IsGlobalContext(),
11148 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011149 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011150 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011151 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011152
11153 // Invoke the result of the compilation to get the evaluation function.
11154 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011155 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011156 Handle<Object> evaluation_function =
11157 Execution::Call(compiled_function, receiver, 0, NULL,
11158 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011159 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011160
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011161 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
11162 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011163 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011164
11165 // Invoke the evaluation function and return the result.
11166 const int argc = 2;
11167 Object** argv[argc] = { arguments.location(),
11168 Handle<Object>::cast(source).location() };
11169 Handle<Object> result =
11170 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11171 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011172 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011173
11174 // Skip the global proxy as it has no properties and always delegates to the
11175 // real global object.
11176 if (result->IsJSGlobalProxy()) {
11177 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11178 }
11179
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011180 return *result;
11181}
11182
11183
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011184RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011185 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011186
11187 // Check the execution state and decode arguments frame and source to be
11188 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011189 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011190 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011191 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11192 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011193 if (!maybe_check_result->ToObject(&check_result)) {
11194 return maybe_check_result;
11195 }
11196 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011197 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011198 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011199 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011200
11201 // Handle the processing of break.
11202 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011203
11204 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011205 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011206 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011207 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011208 top = top->prev();
11209 }
11210 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011211 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011212 }
11213
11214 // Get the global context now set to the top context from before the
11215 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011216 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011217
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011218 bool is_global = true;
11219
11220 if (additional_context->IsJSObject()) {
11221 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011222 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11223 isolate->factory()->empty_string(),
11224 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011225 go_between->set_context(*context);
11226 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011227 isolate->factory()->NewFunctionContext(
11228 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011229 context->set_extension(JSObject::cast(*additional_context));
11230 is_global = false;
11231 }
11232
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011233 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011234 // Currently, the eval code will be executed in non-strict mode,
11235 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011236 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011237 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011238 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011239 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011240 Handle<JSFunction>(
11241 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11242 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011243
11244 // Invoke the result of the compilation to get the evaluation function.
11245 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011246 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011247 Handle<Object> result =
11248 Execution::Call(compiled_function, receiver, 0, NULL,
11249 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011250 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011251 return *result;
11252}
11253
11254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011255RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011256 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011257 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011258
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011259 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011260 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011261
11262 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011263 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011264 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11265 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11266 // because using
11267 // instances->set(i, *GetScriptWrapper(script))
11268 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11269 // already have deferenced the instances handle.
11270 Handle<JSValue> wrapper = GetScriptWrapper(script);
11271 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011272 }
11273
11274 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011275 Handle<JSObject> result =
11276 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011277 Handle<JSArray>::cast(result)->SetContent(*instances);
11278 return *result;
11279}
11280
11281
11282// Helper function used by Runtime_DebugReferencedBy below.
11283static int DebugReferencedBy(JSObject* target,
11284 Object* instance_filter, int max_references,
11285 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011286 JSFunction* arguments_function) {
11287 NoHandleAllocation ha;
11288 AssertNoAllocation no_alloc;
11289
11290 // Iterate the heap.
11291 int count = 0;
11292 JSObject* last = NULL;
11293 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011294 HeapObject* heap_obj = NULL;
11295 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011296 (max_references == 0 || count < max_references)) {
11297 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011298 if (heap_obj->IsJSObject()) {
11299 // Skip context extension objects and argument arrays as these are
11300 // checked in the context of functions using them.
11301 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011302 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011303 obj->map()->constructor() == arguments_function) {
11304 continue;
11305 }
11306
11307 // Check if the JS object has a reference to the object looked for.
11308 if (obj->ReferencesObject(target)) {
11309 // Check instance filter if supplied. This is normally used to avoid
11310 // references from mirror objects (see Runtime_IsInPrototypeChain).
11311 if (!instance_filter->IsUndefined()) {
11312 Object* V = obj;
11313 while (true) {
11314 Object* prototype = V->GetPrototype();
11315 if (prototype->IsNull()) {
11316 break;
11317 }
11318 if (instance_filter == prototype) {
11319 obj = NULL; // Don't add this object.
11320 break;
11321 }
11322 V = prototype;
11323 }
11324 }
11325
11326 if (obj != NULL) {
11327 // Valid reference found add to instance array if supplied an update
11328 // count.
11329 if (instances != NULL && count < instances_size) {
11330 instances->set(count, obj);
11331 }
11332 last = obj;
11333 count++;
11334 }
11335 }
11336 }
11337 }
11338
11339 // Check for circular reference only. This can happen when the object is only
11340 // referenced from mirrors and has a circular reference in which case the
11341 // object is not really alive and would have been garbage collected if not
11342 // referenced from the mirror.
11343 if (count == 1 && last == target) {
11344 count = 0;
11345 }
11346
11347 // Return the number of referencing objects found.
11348 return count;
11349}
11350
11351
11352// Scan the heap for objects with direct references to an object
11353// args[0]: the object to find references to
11354// args[1]: constructor function for instances to exclude (Mirror)
11355// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011356RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011357 ASSERT(args.length() == 3);
11358
11359 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011360 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011361
11362 // Check parameters.
11363 CONVERT_CHECKED(JSObject, target, args[0]);
11364 Object* instance_filter = args[1];
11365 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11366 instance_filter->IsJSObject());
11367 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11368 RUNTIME_ASSERT(max_references >= 0);
11369
11370 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011371 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011372 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011373 JSFunction* arguments_function =
11374 JSFunction::cast(arguments_boilerplate->map()->constructor());
11375
11376 // Get the number of referencing objects.
11377 int count;
11378 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011379 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011380
11381 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011382 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011383 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011384 if (!maybe_object->ToObject(&object)) return maybe_object;
11385 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011386 FixedArray* instances = FixedArray::cast(object);
11387
11388 // Fill the referencing objects.
11389 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011390 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011391
11392 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011393 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011394 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11395 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011396 if (!maybe_result->ToObject(&result)) return maybe_result;
11397 }
11398 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011399 return result;
11400}
11401
11402
11403// Helper function used by Runtime_DebugConstructedBy below.
11404static int DebugConstructedBy(JSFunction* constructor, int max_references,
11405 FixedArray* instances, int instances_size) {
11406 AssertNoAllocation no_alloc;
11407
11408 // Iterate the heap.
11409 int count = 0;
11410 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011411 HeapObject* heap_obj = NULL;
11412 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011413 (max_references == 0 || count < max_references)) {
11414 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011415 if (heap_obj->IsJSObject()) {
11416 JSObject* obj = JSObject::cast(heap_obj);
11417 if (obj->map()->constructor() == constructor) {
11418 // Valid reference found add to instance array if supplied an update
11419 // count.
11420 if (instances != NULL && count < instances_size) {
11421 instances->set(count, obj);
11422 }
11423 count++;
11424 }
11425 }
11426 }
11427
11428 // Return the number of referencing objects found.
11429 return count;
11430}
11431
11432
11433// Scan the heap for objects constructed by a specific function.
11434// args[0]: the constructor to find instances of
11435// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011436RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011437 ASSERT(args.length() == 2);
11438
11439 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011440 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011441
11442 // Check parameters.
11443 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11444 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11445 RUNTIME_ASSERT(max_references >= 0);
11446
11447 // Get the number of referencing objects.
11448 int count;
11449 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11450
11451 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011452 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011453 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011454 if (!maybe_object->ToObject(&object)) return maybe_object;
11455 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011456 FixedArray* instances = FixedArray::cast(object);
11457
11458 // Fill the referencing objects.
11459 count = DebugConstructedBy(constructor, max_references, instances, count);
11460
11461 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011462 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011463 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11464 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011465 if (!maybe_result->ToObject(&result)) return maybe_result;
11466 }
11467 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011468 return result;
11469}
11470
11471
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011472// Find the effective prototype object as returned by __proto__.
11473// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011474RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011475 ASSERT(args.length() == 1);
11476
11477 CONVERT_CHECKED(JSObject, obj, args[0]);
11478
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011479 // Use the __proto__ accessor.
11480 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011481}
11482
11483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011484RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011485 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011486 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011487 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011488}
11489
11490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011491RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011492#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011493 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011494 ASSERT(args.length() == 1);
11495 // Get the function and make sure it is compiled.
11496 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011497 Handle<SharedFunctionInfo> shared(func->shared());
11498 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011499 return Failure::Exception();
11500 }
11501 func->code()->PrintLn();
11502#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011503 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011504}
ager@chromium.org9085a012009-05-11 19:22:57 +000011505
11506
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011507RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011508#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011509 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011510 ASSERT(args.length() == 1);
11511 // Get the function and make sure it is compiled.
11512 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011513 Handle<SharedFunctionInfo> shared(func->shared());
11514 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011515 return Failure::Exception();
11516 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011517 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011518#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011519 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011520}
11521
11522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011523RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011524 NoHandleAllocation ha;
11525 ASSERT(args.length() == 1);
11526
11527 CONVERT_CHECKED(JSFunction, f, args[0]);
11528 return f->shared()->inferred_name();
11529}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011530
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011531
11532static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011533 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011534 AssertNoAllocation no_allocations;
11535
11536 int counter = 0;
11537 int buffer_size = buffer->length();
11538 HeapIterator iterator;
11539 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11540 ASSERT(obj != NULL);
11541 if (!obj->IsSharedFunctionInfo()) {
11542 continue;
11543 }
11544 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11545 if (shared->script() != script) {
11546 continue;
11547 }
11548 if (counter < buffer_size) {
11549 buffer->set(counter, shared);
11550 }
11551 counter++;
11552 }
11553 return counter;
11554}
11555
11556// For a script finds all SharedFunctionInfo's in the heap that points
11557// to this script. Returns JSArray of SharedFunctionInfo wrapped
11558// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011559RUNTIME_FUNCTION(MaybeObject*,
11560 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011561 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011562 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011563 CONVERT_CHECKED(JSValue, script_value, args[0]);
11564
11565 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11566
11567 const int kBufferSize = 32;
11568
11569 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011570 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011571 int number = FindSharedFunctionInfosForScript(*script, *array);
11572 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011573 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011574 FindSharedFunctionInfosForScript(*script, *array);
11575 }
11576
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011577 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011578 result->set_length(Smi::FromInt(number));
11579
11580 LiveEdit::WrapSharedFunctionInfos(result);
11581
11582 return *result;
11583}
11584
11585// For a script calculates compilation information about all its functions.
11586// The script source is explicitly specified by the second argument.
11587// The source of the actual script is not used, however it is important that
11588// all generated code keeps references to this particular instance of script.
11589// Returns a JSArray of compilation infos. The array is ordered so that
11590// each function with all its descendant is always stored in a continues range
11591// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011592RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011593 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011594 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011595 CONVERT_CHECKED(JSValue, script, args[0]);
11596 CONVERT_ARG_CHECKED(String, source, 1);
11597 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11598
11599 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11600
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011601 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011602 return Failure::Exception();
11603 }
11604
11605 return result;
11606}
11607
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011608// Changes the source of the script to a new_source.
11609// If old_script_name is provided (i.e. is a String), also creates a copy of
11610// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011611RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011612 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011613 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011614 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11615 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011616 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011617
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011618 CONVERT_CHECKED(Script, original_script_pointer,
11619 original_script_value->value());
11620 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011621
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011622 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11623 new_source,
11624 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011625
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011626 if (old_script->IsScript()) {
11627 Handle<Script> script_handle(Script::cast(old_script));
11628 return *(GetScriptWrapper(script_handle));
11629 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011630 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011631 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011632}
11633
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011634
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011635RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011636 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011637 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011638 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11639 return LiveEdit::FunctionSourceUpdated(shared_info);
11640}
11641
11642
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011643// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011644RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011645 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011647 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11648 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11649
ager@chromium.orgac091b72010-05-05 07:34:42 +000011650 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011651}
11652
11653// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011654RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011655 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011656 HandleScope scope(isolate);
11657 Handle<Object> function_object(args[0], isolate);
11658 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011659
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011660 if (function_object->IsJSValue()) {
11661 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11662 if (script_object->IsJSValue()) {
11663 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011664 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011665 }
11666
11667 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11668 } else {
11669 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11670 // and we check it in this function.
11671 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011672
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011673 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011674}
11675
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011676
11677// In a code of a parent function replaces original function as embedded object
11678// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011679RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011680 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011681 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011682
11683 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11684 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11685 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11686
11687 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11688 subst_wrapper);
11689
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011690 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011691}
11692
11693
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011694// Updates positions of a shared function info (first parameter) according
11695// to script source change. Text change is described in second parameter as
11696// array of groups of 3 numbers:
11697// (change_begin, change_end, change_end_new_position).
11698// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011699RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011700 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011701 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011702 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11703 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11704
ager@chromium.orgac091b72010-05-05 07:34:42 +000011705 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011706}
11707
11708
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011709// For array of SharedFunctionInfo's (each wrapped in JSValue)
11710// checks that none of them have activations on stacks (of any thread).
11711// Returns array of the same length with corresponding results of
11712// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011713RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011714 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011715 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011716 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011717 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011718
ager@chromium.org357bf652010-04-12 11:30:10 +000011719 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011720}
11721
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011722// Compares 2 strings line-by-line, then token-wise and returns diff in form
11723// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11724// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011725RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011726 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011727 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011728 CONVERT_ARG_CHECKED(String, s1, 0);
11729 CONVERT_ARG_CHECKED(String, s2, 1);
11730
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011731 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011732}
11733
11734
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011735// A testing entry. Returns statement position which is the closest to
11736// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011737RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011738 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011739 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011740 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11741 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11742
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011743 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011744
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011745 if (code->kind() != Code::FUNCTION &&
11746 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011747 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011748 }
11749
11750 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011751 int closest_pc = 0;
11752 int distance = kMaxInt;
11753 while (!it.done()) {
11754 int statement_position = static_cast<int>(it.rinfo()->data());
11755 // Check if this break point is closer that what was previously found.
11756 if (source_position <= statement_position &&
11757 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011758 closest_pc =
11759 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011760 distance = statement_position - source_position;
11761 // Check whether we can't get any closer.
11762 if (distance == 0) break;
11763 }
11764 it.next();
11765 }
11766
11767 return Smi::FromInt(closest_pc);
11768}
11769
11770
ager@chromium.org357bf652010-04-12 11:30:10 +000011771// Calls specified function with or without entering the debugger.
11772// This is used in unit tests to run code as if debugger is entered or simply
11773// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011774RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011775 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011776 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011777 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11778 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11779
11780 Handle<Object> result;
11781 bool pending_exception;
11782 {
11783 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011784 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011785 &pending_exception);
11786 } else {
11787 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011788 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011789 &pending_exception);
11790 }
11791 }
11792 if (!pending_exception) {
11793 return *result;
11794 } else {
11795 return Failure::Exception();
11796 }
11797}
11798
11799
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011800// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011801RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011802 CONVERT_CHECKED(String, arg, args[0]);
11803 SmartPointer<char> flags =
11804 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11805 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011806 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011807}
11808
11809
11810// Performs a GC.
11811// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011812RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011813 isolate->heap()->CollectAllGarbage(true);
11814 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011815}
11816
11817
11818// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011819RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011820 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011821 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011822 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011823 }
11824 return Smi::FromInt(usage);
11825}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011826
11827
11828// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011829RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011830#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011831 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011832#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011833 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011834#endif
11835}
11836
11837
11838// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011839RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011840#ifdef LIVE_OBJECT_LIST
11841 return LiveObjectList::Capture();
11842#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011843 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011844#endif
11845}
11846
11847
11848// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011849RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011850#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011851 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011852 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011853 return success ? isolate->heap()->true_value() :
11854 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011855#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011856 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011857#endif
11858}
11859
11860
11861// Generates the response to a debugger request for a dump of the objects
11862// contained in the difference between the captured live object lists
11863// specified by id1 and id2.
11864// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11865// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011866RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011867#ifdef LIVE_OBJECT_LIST
11868 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011869 CONVERT_SMI_ARG_CHECKED(id1, 0);
11870 CONVERT_SMI_ARG_CHECKED(id2, 1);
11871 CONVERT_SMI_ARG_CHECKED(start, 2);
11872 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011873 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11874 EnterDebugger enter_debugger;
11875 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11876#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011877 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011878#endif
11879}
11880
11881
11882// Gets the specified object as requested by the debugger.
11883// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011884RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011885#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011886 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011887 Object* result = LiveObjectList::GetObj(obj_id);
11888 return result;
11889#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011890 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011891#endif
11892}
11893
11894
11895// Gets the obj id for the specified address if valid.
11896// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011897RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011898#ifdef LIVE_OBJECT_LIST
11899 HandleScope scope;
11900 CONVERT_ARG_CHECKED(String, address, 0);
11901 Object* result = LiveObjectList::GetObjId(address);
11902 return result;
11903#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011904 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011905#endif
11906}
11907
11908
11909// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011910RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011911#ifdef LIVE_OBJECT_LIST
11912 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011913 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011914 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11915 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11916 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11917 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11918 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11919
11920 Handle<JSObject> instance_filter;
11921 if (args[1]->IsJSObject()) {
11922 instance_filter = args.at<JSObject>(1);
11923 }
11924 bool verbose = false;
11925 if (args[2]->IsBoolean()) {
11926 verbose = args[2]->IsTrue();
11927 }
11928 int start = 0;
11929 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011930 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011931 }
11932 int limit = Smi::kMaxValue;
11933 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011934 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011935 }
11936
11937 return LiveObjectList::GetObjRetainers(obj_id,
11938 instance_filter,
11939 verbose,
11940 start,
11941 limit,
11942 filter_obj);
11943#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011944 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011945#endif
11946}
11947
11948
11949// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011950RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011951#ifdef LIVE_OBJECT_LIST
11952 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011953 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
11954 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011955 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11956
11957 Handle<JSObject> instance_filter;
11958 if (args[2]->IsJSObject()) {
11959 instance_filter = args.at<JSObject>(2);
11960 }
11961
11962 Object* result =
11963 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11964 return result;
11965#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011966 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011967#endif
11968}
11969
11970
11971// Generates the response to a debugger request for a list of all
11972// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011973RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011974#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011975 CONVERT_SMI_ARG_CHECKED(start, 0);
11976 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011977 return LiveObjectList::Info(start, count);
11978#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011979 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011980#endif
11981}
11982
11983
11984// Gets a dump of the specified object as requested by the debugger.
11985// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011986RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011987#ifdef LIVE_OBJECT_LIST
11988 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011989 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011990 Object* result = LiveObjectList::PrintObj(obj_id);
11991 return result;
11992#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011993 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011994#endif
11995}
11996
11997
11998// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011999RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012000#ifdef LIVE_OBJECT_LIST
12001 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012002 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012003#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012004 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012005#endif
12006}
12007
12008
12009// Generates the response to a debugger request for a summary of the types
12010// of objects in the difference between the captured live object lists
12011// specified by id1 and id2.
12012// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12013// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012014RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012015#ifdef LIVE_OBJECT_LIST
12016 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012017 CONVERT_SMI_ARG_CHECKED(id1, 0);
12018 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012019 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12020
12021 EnterDebugger enter_debugger;
12022 return LiveObjectList::Summarize(id1, id2, filter_obj);
12023#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012024 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012025#endif
12026}
12027
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012028#endif // ENABLE_DEBUGGER_SUPPORT
12029
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012030
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012031#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012032RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012033 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000012034 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012035
12036 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000012037 CONVERT_CHECKED(Smi, smi_tag, args[1]);
12038 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012039 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012040}
12041
12042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012043RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012044 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000012045 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012046
12047 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000012048 CONVERT_CHECKED(Smi, smi_tag, args[1]);
12049 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012050 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012051}
12052
12053#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012054
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012055// Finds the script object from the script data. NOTE: This operation uses
12056// heap traversal to find the function generated for the source position
12057// for the requested break point. For lazily compiled functions several heap
12058// traversals might be required rendering this operation as a rather slow
12059// operation. However for setting break points which is normally done through
12060// some kind of user interaction the performance is not crucial.
12061static Handle<Object> Runtime_GetScriptFromScriptName(
12062 Handle<String> script_name) {
12063 // Scan the heap for Script objects to find the script with the requested
12064 // script data.
12065 Handle<Script> script;
12066 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012067 HeapObject* obj = NULL;
12068 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012069 // If a script is found check if it has the script data requested.
12070 if (obj->IsScript()) {
12071 if (Script::cast(obj)->name()->IsString()) {
12072 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12073 script = Handle<Script>(Script::cast(obj));
12074 }
12075 }
12076 }
12077 }
12078
12079 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012080 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012081
12082 // Return the script found.
12083 return GetScriptWrapper(script);
12084}
12085
12086
12087// Get the script object from script data. NOTE: Regarding performance
12088// see the NOTE for GetScriptFromScriptData.
12089// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012090RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012091 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012092
12093 ASSERT(args.length() == 1);
12094
12095 CONVERT_CHECKED(String, script_name, args[0]);
12096
12097 // Find the requested script.
12098 Handle<Object> result =
12099 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12100 return *result;
12101}
12102
12103
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012104// Determines whether the given stack frame should be displayed in
12105// a stack trace. The caller is the error constructor that asked
12106// for the stack trace to be collected. The first time a construct
12107// call to this function is encountered it is skipped. The seen_caller
12108// in/out parameter is used to remember if the caller has been seen
12109// yet.
12110static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
12111 bool* seen_caller) {
12112 // Only display JS frames.
12113 if (!raw_frame->is_java_script())
12114 return false;
12115 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12116 Object* raw_fun = frame->function();
12117 // Not sure when this can happen but skip it just in case.
12118 if (!raw_fun->IsJSFunction())
12119 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012120 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012121 *seen_caller = true;
12122 return false;
12123 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012124 // Skip all frames until we've seen the caller. Also, skip the most
12125 // obvious builtin calls. Some builtin calls (such as Number.ADD
12126 // which is invoked using 'call') are very difficult to recognize
12127 // so we're leaving them in for now.
12128 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012129}
12130
12131
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012132// Collect the raw data for a stack trace. Returns an array of 4
12133// element segments each containing a receiver, function, code and
12134// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012135RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012136 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012137 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012138 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12139
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012140 HandleScope scope(isolate);
12141 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012142
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012143 limit = Max(limit, 0); // Ensure that limit is not negative.
12144 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012145 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012146 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012147
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012148 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012149 // If the caller parameter is a function we skip frames until we're
12150 // under it before starting to collect.
12151 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012152 int cursor = 0;
12153 int frames_seen = 0;
12154 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012155 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012156 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012157 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012158 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012159 // Set initial size to the maximum inlining level + 1 for the outermost
12160 // function.
12161 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012162 frame->Summarize(&frames);
12163 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012164 if (cursor + 4 > elements->length()) {
12165 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12166 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012167 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012168 for (int i = 0; i < cursor; i++) {
12169 new_elements->set(i, elements->get(i));
12170 }
12171 elements = new_elements;
12172 }
12173 ASSERT(cursor + 4 <= elements->length());
12174
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012175 Handle<Object> recv = frames[i].receiver();
12176 Handle<JSFunction> fun = frames[i].function();
12177 Handle<Code> code = frames[i].code();
12178 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012179 elements->set(cursor++, *recv);
12180 elements->set(cursor++, *fun);
12181 elements->set(cursor++, *code);
12182 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012183 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012184 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012185 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012186 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012187 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012188 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012189 return *result;
12190}
12191
12192
ager@chromium.org3811b432009-10-28 14:53:37 +000012193// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012194RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012195 ASSERT_EQ(args.length(), 0);
12196
12197 NoHandleAllocation ha;
12198
12199 const char* version_string = v8::V8::GetVersion();
12200
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012201 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12202 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012203}
12204
12205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012206RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012207 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012208 OS::PrintError("abort: %s\n",
12209 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012210 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012211 OS::Abort();
12212 UNREACHABLE();
12213 return NULL;
12214}
12215
12216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012217RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012218 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012219 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012220 Object* key = args[1];
12221
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012222 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012223 Object* o = cache->get(finger_index);
12224 if (o == key) {
12225 // The fastest case: hit the same place again.
12226 return cache->get(finger_index + 1);
12227 }
12228
12229 for (int i = finger_index - 2;
12230 i >= JSFunctionResultCache::kEntriesIndex;
12231 i -= 2) {
12232 o = cache->get(i);
12233 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012234 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012235 return cache->get(i + 1);
12236 }
12237 }
12238
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012239 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012240 ASSERT(size <= cache->length());
12241
12242 for (int i = size - 2; i > finger_index; i -= 2) {
12243 o = cache->get(i);
12244 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012245 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012246 return cache->get(i + 1);
12247 }
12248 }
12249
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012250 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012251 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012252
12253 Handle<JSFunctionResultCache> cache_handle(cache);
12254 Handle<Object> key_handle(key);
12255 Handle<Object> value;
12256 {
12257 Handle<JSFunction> factory(JSFunction::cast(
12258 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12259 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012260 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012261 // This handle is nor shared, nor used later, so it's safe.
12262 Object** argv[] = { key_handle.location() };
12263 bool pending_exception = false;
12264 value = Execution::Call(factory,
12265 receiver,
12266 1,
12267 argv,
12268 &pending_exception);
12269 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012270 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012271
12272#ifdef DEBUG
12273 cache_handle->JSFunctionResultCacheVerify();
12274#endif
12275
12276 // Function invocation may have cleared the cache. Reread all the data.
12277 finger_index = cache_handle->finger_index();
12278 size = cache_handle->size();
12279
12280 // If we have spare room, put new data into it, otherwise evict post finger
12281 // entry which is likely to be the least recently used.
12282 int index = -1;
12283 if (size < cache_handle->length()) {
12284 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12285 index = size;
12286 } else {
12287 index = finger_index + JSFunctionResultCache::kEntrySize;
12288 if (index == cache_handle->length()) {
12289 index = JSFunctionResultCache::kEntriesIndex;
12290 }
12291 }
12292
12293 ASSERT(index % 2 == 0);
12294 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12295 ASSERT(index < cache_handle->length());
12296
12297 cache_handle->set(index, *key_handle);
12298 cache_handle->set(index + 1, *value);
12299 cache_handle->set_finger_index(index);
12300
12301#ifdef DEBUG
12302 cache_handle->JSFunctionResultCacheVerify();
12303#endif
12304
12305 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012306}
12307
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012308
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012309RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012310 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012311 CONVERT_ARG_CHECKED(String, type, 0);
12312 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012313 return *isolate->factory()->NewJSMessageObject(
12314 type,
12315 arguments,
12316 0,
12317 0,
12318 isolate->factory()->undefined_value(),
12319 isolate->factory()->undefined_value(),
12320 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012321}
12322
12323
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012324RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012325 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12326 return message->type();
12327}
12328
12329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012330RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012331 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12332 return message->arguments();
12333}
12334
12335
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012336RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012337 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12338 return Smi::FromInt(message->start_position());
12339}
12340
12341
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012342RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012343 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12344 return message->script();
12345}
12346
12347
kasper.lund44510672008-07-25 07:37:58 +000012348#ifdef DEBUG
12349// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12350// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012351RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012352 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012353 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012354#define COUNT_ENTRY(Name, argc, ressize) + 1
12355 int entry_count = 0
12356 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12357 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12358 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12359#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012360 Factory* factory = isolate->factory();
12361 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012362 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012363 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012364#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012365 { \
12366 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012367 Handle<String> name; \
12368 /* Inline runtime functions have an underscore in front of the name. */ \
12369 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012370 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012371 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12372 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012373 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012374 Vector<const char>(#Name, StrLength(#Name))); \
12375 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012376 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012377 pair_elements->set(0, *name); \
12378 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012379 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012380 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012381 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012382 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012383 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012384 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012385 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012386 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012387#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012388 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012389 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012390 return *result;
12391}
kasper.lund44510672008-07-25 07:37:58 +000012392#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012393
12394
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012395RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012396 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012397 CONVERT_CHECKED(String, format, args[0]);
12398 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012399 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012400 LOGGER->LogRuntime(chars, elms);
12401 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012402}
12403
12404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012405RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012406 UNREACHABLE(); // implemented as macro in the parser
12407 return NULL;
12408}
12409
12410
12411// ----------------------------------------------------------------------------
12412// Implementation of Runtime
12413
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012414#define F(name, number_of_args, result_size) \
12415 { Runtime::k##name, Runtime::RUNTIME, #name, \
12416 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012417
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012418
12419#define I(name, number_of_args, result_size) \
12420 { Runtime::kInline##name, Runtime::INLINE, \
12421 "_" #name, NULL, number_of_args, result_size },
12422
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012423static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012424 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012425 INLINE_FUNCTION_LIST(I)
12426 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012427};
12428
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012430MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12431 Object* dictionary) {
12432 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012433 ASSERT(dictionary != NULL);
12434 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12435 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012436 Object* name_symbol;
12437 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012438 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012439 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12440 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012441 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012442 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12443 String::cast(name_symbol),
12444 Smi::FromInt(i),
12445 PropertyDetails(NONE, NORMAL));
12446 if (!maybe_dictionary->ToObject(&dictionary)) {
12447 // Non-recoverable failure. Calling code must restart heap
12448 // initialization.
12449 return maybe_dictionary;
12450 }
12451 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012452 }
12453 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012454}
12455
12456
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012457const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12458 Heap* heap = name->GetHeap();
12459 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012460 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012461 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012462 int function_index = Smi::cast(smi_index)->value();
12463 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012464 }
12465 return NULL;
12466}
12467
12468
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012469const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012470 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12471}
12472
12473
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012474void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012475 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012476 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012477 if (failure->IsRetryAfterGC()) {
12478 // Try to do a garbage collection; ignore it if it fails. The C
12479 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012480 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012481 } else {
12482 // Handle last resort GC and make sure to allow future allocations
12483 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012484 isolate->counters()->gc_last_resort_from_js()->Increment();
12485 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012486 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012487}
12488
12489
12490} } // namespace v8::internal